Release Notes 2026-09-14

Release Notes 2026-09-14

Version Information

OpenEdge Release

Version Information

OpenEdge Release

Version Information

11.7.21, 12.2.19, 12.8.9, 12.8.11, 12.8.12, 13.0.0

Release 11.7 #89567@2026-09-14

Retirement of OpenEdge 11.7

OpenEdge 11.7 has been retired by Progress Software on April 1st 2025. In consequence we urge all customers still using OpenEdge 11 to upgrade to OpenEdge 12.2 or 12.8 as soon as possible.

We are intending to drop the official support of the SmartComponent Library for OpenEdge 11.7 during the second half of the year 2025. We will then no longer ensure that new features of the framework will be usable with OpenEdge 11.7

Customers that are concerned by this intention, should reach out to us as soon as possible, so that we can discuss about a solution.

OpenEdge 13.0 support!

We are pleased to announce that we are not aware of any issues using the SmartComponent Library on OpenEdge 13.0. We hereby declare OpenEdge 13.0 fully supported for the SmartComponent Library as of the release of February 15th 2026.

OpenEdge 12.8 support!

We are pleased to announce that we are not aware of any issues using the SmartComponent Library on OpenEdge 12.8. We hereby declare OpenEdge 12.8 fully supported for the SmartComponent Library as of the release of January 15th 2024.

OpenEdge 12.2 support!

We are pleased to announce that we are not aware of any issues using the SmartComponent Library on OpenEdge 12.2. We hereby declare OpenEdge 12.2 fully supported for the SmartComponent Library as of the release of April 09th 2020.

PASOE / OEMANAGER VS Code Extension

Our first VS Code extension is available in the VS Code marketplace: https://marketplace.visualstudio.com/items?itemName=ConsultingwerkApplicationModernizationSolutionsLtd.oemanager

The extension supports developers with PASOE related routine tasks during development:

  • checking agent or session status

  • trimming the PASOE agents

  • restarting a new agent vai the ping request

Introducing the SmartComponent Library developer forum

Got questions about using the SmartComponent Library? Wish to discuss feature requests with other users of the SmartComponent Library? To facilitate networking in the growing number of SmartComponent Library users and developers, we've added a developer forum on our new home-page. The developer forum can be found at: https://www.consultingwerk.com/support/forum

A login is required to participate in the forum. Don't be shy - create your account today!

Release Notes

Following the release of the OpenEdge 11.7 Release we have completed our testing of the SmartComponent Library on this release of Progress and are proud to announce formal support for the SmartComponent Library on OpenEdge 11.7 with the 2017-04-24 release of the SmartComponent Library. Generally we recommend customers on OpenEdge 11 to upgrade to OpenEdge 11.7 quickly. Starting the 2017-07-14 release we are supporting OpenEdge 11.7 Service Pack 1 (11.7.1).

Starting the 2015-10-09 release the Business Entity Designer will feature a start page with links to most recent release note articles on this site.

With SCL-751 we have adopted native Enums for OpenEdge 11.6. To activate this feature customers must add a definition to products.i. SCL-751 provides details for this.

With SCL-1113 we have modified the templates for SmartWindowForms and SmartTabFolderPages generated from the Business Entity Designer. We have removed the initialization of the viewer controls SmartTableIOState property (value was set to "NoDataSource" within the InitializeComponent method). Customers using their own set of templates should adopt the same fix to their templates.

New Versions of Proparse .NET Assemblies (30 December 2018)

We have updated proparse with further enhancements in this release (see https://github.com/consultingwerk/proparse/releases/tag/4.0.1.1177). Please download the .NET Assemblies ZIP file from our ESD and replace the proparse.net.dll in your environment with the latest one. The new assembly reference is:

<assembly name="proparse.net, Version=4.0.1.1177, Culture=neutral, PublicKeyToken=cda1b098b1034b24"/>

As proparse is used by our Business Entity Generator, this new version of the proparse.net Assembly is also relevant for customers not doing GUI for .NET development and require support for parsing new ABL language constructs.

This version of proparse provides additional debug information when errors are thrown from proparse.net.dll.

New Version of the Consultingwerk.SmartComponents Assemly (09 January 2019)

To support the new SmartFilterControl and the "Filter" link between the SmartFilterControl/SmartDynamciFilterControl and a SmartBusinessEntityAdapter or SmartDatasetChildAdapter we have updated the Consultingwerk.SmartComponents.dll. The new Assembly reference is:

<assembly name="Consultingwerk.SmartComponents, Version=2.2.0.49856, Culture=neutral, PublicKeyToken=10603cb31df311b3"/>

Customers need to update this Assembly in order to compile the latest releases of the SmartComponent Library.

Hybrid Realm now using IAuthenticationService

We've updated the SmartHybridRealm class used for http authentication to leverage the IAuthenticationService. It is therefor required that for AppServers requiring http Authentication (e.g. REST or Web) the correct IAuthenticationService implementation is registered (using service.xml files).

Customers relying on the previous behavior should ensure that the Consultingwerk.SmartFramework.Authentication.AuthenticationService is regsitered as the IAuthenticationService. This implementation will auhtenticate users against the password stored in the SmartUser database table.

When users with no Login Company set should be able to login using the SmartHybridRealm, it's required to set the Login Company Tennant Domain (similar to the field in the Login Company Maintenance) in the .restapplicationsettings / .applicationsettings, e.g.:

 

"DefaultAuthenticationDomain": "consultingwerk"

This is required as the Hydrid Realm Interface from Progress does not provide the domain name to the authentication method.

Web Handler overview

This is an overview of the web handlers supported by this release

defaultHandler=OpenEdge.Web.CompatibilityHandler handler1=Consultingwerk.OERA.JsdoGenericService.WebHandler.CatalogWebHandler: /Catalog/{EntityName} handler2=Consultingwerk.OERA.JsdoGenericService.WebHandler.CatalogsWebHandler: /Catalogs/{PackageName} handler3=Consultingwerk.OERA.JsdoGenericService.WebHandler.CountWebHandler: /Resource/{EntityName}/count handler4=Consultingwerk.OERA.JsdoGenericService.WebHandler.ResourceSubmitWebHandler: /Resource/{EntityName}/SubmitData handler5=Consultingwerk.OERA.JsdoGenericService.WebHandler.InvokeMethodWebHandler: /Resource/{EntityName}/{MethodName} handler6=Consultingwerk.OERA.JsdoGenericService.WebHandler.ResourceWebHandler: /Resource/{EntityName} handler7=Consultingwerk.OERA.JsdoGenericService.WebHandler.BusinessServicesWebHandler: /BusinessServices/{OutputFormat}/{PackageName} handler8=Consultingwerk.Web2.WebHandler.SmartMenuWebHandler: /SmartMenu/{MenuStructureId} handler9=Consultingwerk.Web2.WebHandler.SmartMenuStructureWebHandler: /SmartMenuStructure handler10=Consultingwerk.Web2.WebHandler.SmartRoutesWebHandler: /SmartRoutes handler11=Consultingwerk.Web2.Services.SmartViewsHandler.SmartGridWebHandler: /SmartViews/Grid/{EntityName}/{ViewName}/{DetailTemplate} handler12=Consultingwerk.Web2.Services.SmartViewsHandler.SmartGridWebHandler: /SmartViews/Grid/{EntityName}/{ViewName} handler13=Consultingwerk.Web2.Services.SmartViewsHandler.SmartGridWebHandler: /SmartViews/Grid/{CustomViewName} handler14=Consultingwerk.Web2.Services.SmartViewsHandler.SmartViewerWebHandler: /SmartViewer/Viewer/{EntityName}/{ViewName} handler15=Consultingwerk.Web2.Services.SmartViewsHandler.SmartViewerWebHandler: /SmartViewer/Viewer/{ObjectName} handler16=Consultingwerk.Web2.Services.SmartViewsHandler.SmartFormWebHandler: /SmartForm/{FormTemplate}/{EntityName}/{ViewName} handler17=Consultingwerk.Web2.Services.SmartViewsHandler.SmartFormWebHandler: /SmartForm/{FormTemplate}/{ObjectName} handler18=Consultingwerk.Web2.WebHandler.SmartMessageWebHandler: /SmartMessage/{MessageGroup}/{MessageNumber} handler19=Consultingwerk.Web2.WebHandler.GetImageWebHandler: /Image/{FileName} handler20=Consultingwerk.Web2.WebHandler.SmartValueListWebHandler: /ValueList/{ValueList} handler21=Consultingwerk.Web2.WebHandler.SmartAttachmentsWebHandler: /Attachments/{Table}/{KeyValues} handler22=Consultingwerk.Web2.WebHandler.SmartAttachmentWebHandler: /Attachment/{Guid} handler23=Consultingwerk.Web2.WebHandler.SessionContextWebHandler: /SessionContext handler24=Consultingwerk.Web2.WebHandler.ContextPropertiesWebHandler: /ContextProperties/{PropertyName} handler25=Consultingwerk.Web2.WebHandler.ContextPropertiesWebHandler: /ContextProperties handler26=Consultingwerk.Web2.WebHandler.SessionInfoWebHandler: /SessionInfo handler27=Consultingwerk.Web2.WebHandler.FileSearchWebHandler: /FileSearch/{FileName} handler28=Consultingwerk.Web2.WebHandler.ExecuteAblWebHandler: /ExecuteAbl handler29=Consultingwerk.Web2.WebHandler.SmartLanguagesWebHandler: /Languages handler30=Consultingwerk.OERA.RestResource.RestEntitiesWebHandler: /Entities handler31=Consultingwerk.OERA.Swagger.SwaggerWebHandler: /Swagger/{EntityName} handler32=Consultingwerk.OERA.Swagger.SwaggerRestEntitiesWebHandler: /SwaggerEntities/{OutputType} handler33=Consultingwerk.Web2.WebHandler.SmartTokenSecurityCheckWebHandler: /TokenSecurityCheck/{ObjectName} handler34=Consultingwerk.Web2.WebHandler.SmartTokenSecurityCheckWebHandler: /TokenSecurityCheck handler35=Consultingwerk.Web2.WebHandler.SmartEntityTableMappingHandler: /EntityTableMapping/{EntityName}/{TableName}/{UiTypeCodes} handler36=Consultingwerk.Web2.WebHandler.SmartTreeRootNodeWebHandler: /SmartViews/TreeRootNode/{rootnodeid} handler37=Consultingwerk.Web2.WebHandler.SmartTreeChildNodesWebHandler: /SmartViews/TreeChildNodes/{parentnodeid} handler38=Consultingwerk.Web2.WebHandler.SmartSecurityCheckWebHandler: /IsRestricted/{SecurityRealmCode}/{SecurityItemGuid} handler39=Consultingwerk.Web2.WebHandler.SmartFieldSecurityCheckWebHandler: /RestrictedFields/{TableName} handler40=Consultingwerk.Web2.WebHandler.GetImageNamesHandler: /ImageNames handler41=Consultingwerk.Web2.WebHandler.ExecuteQueryWebHandler: /ExecuteQuery handler42=Consultingwerk.Web2.WebHandler.TranslationProviderWebHandler: /GetTranslation

UTF-8 based deployments available

Starting August 14th 2016 we ship our source code also as UTF-8 encoded. The ZIP files ending with _utf8.zip contain the source code encoded with that code page. The source code in the remaining archives is still encoded in ISO8859-1. Also on Github there is a new branch containing the OpenEdge 11 based source code in UTF-8.

Related article (Progress K-Base): How to get Progress Developer Studio to save in UTF-8 encoding

New Feature Documentation

Download Link

http://esd.consultingwerkcloud.com/

https://github.com/consultingwerk/SmartComponentLibrary

Overview of included tickets

Tree view nodes can now be refreshed from the node provider after a record has been saved

A new optional provider interface ISmartTreeNodeRefreshProvider with a GetNode (node type, key values) method returns the refreshed SerializableTreeNode; the SmartTreeNodeProviderRegistry consults all registered providers that implement it. The new web handler Consultingwerk.Web2.WebHandler.SmartTreeNodeWebHandler exposes this to the Angular client as GET /SmartViews/TreeNode/{nodetype} and returns HTTP 404 when no provider serves the node type. In the GUI for .NET the DynamicTreeViewControl can refresh a single node, and the DynamicTreeViewForm does so after the data source of the rendered detail panel has saved a record, so node values such as the item name of an order line follow the update. The existing ISmartTreeNodeProvider interface is unchanged, so existing providers keep compiling; implement the new interface where node values should be refreshed, as demonstrated by the OrderPresentationTreeViewNodeProvider.

Menu controls can now be rendered from the Repository on a Form

A Repository rendering component for menu structures has been added, allowing a menu to be designed in the Repository and rendered on a Form at runtime. The component supports the new menuType attribute, so developers can control which kind of menu is generated. Add the menu control to a Repository Object in the Dynamics designer and set the menuType attribute to use it.

Annotation based record description provider for Business Entity temp-tables

A short, human readable description of any Business Entity temp-table record (for example "Lift Tours / Burlington") can now be obtained through the new Consultingwerk.OERA.IBusinessEntityDescriptionProvider and its default implementation Consultingwerk.OERA.BusinessEntityDescriptionProvider, using the same API on the server and on the client. The description is defined declaratively in the Business Entity through the new DescriptionFields, DescriptionSubstitute and DescriptionFormats attributes of the @BusinessEntityTable annotation; these are surfaced by IBusinessEntityTableDescriptor, so the client obtains them with the Business Entity Descriptor without an additional round trip. Obtain a provider with BusinessEntityDescriptionProvider:FromEntityName (or FromEntity) and call GetRecordDescription with either a buffer handle or an IBufferHandle such as a generated TableModel; providers are registered as keyed services under the entity name, so a project can replace the description logic for a single Business Entity. When a Business Entity provides no description annotations, the provider falls back to the first five buffer fields that are not GUID, CLOB, BLOB, RAW or array fields. No changes are required in existing customer code.

Multiple lookups with FetchDataByKeyValue are now resolved in a single server request

Several FetchDataByKeyValue lookups are now combined into a single server request instead of one request per lookup, and dependencies between those lookups are resolved on the server. This reduces the number of round trips for screens that resolve multiple key values at once. No changes required in customer code.

Grid filter row now supports value lists

Following up on the value list support for grid cells, the value list of a column is now also assigned to the corresponding cell of the grid filter row. Users therefore filter such a column by selecting one of its descriptive values instead of typing the raw stored value. The value list is taken from the existing column definition, so no additional configuration is required in customer code.

Single sign-on for the Angular web application embedded into the Desktop application

When an Angular web application is embedded into the Desktop application through the AngularPreviewForm, the user is no longer required to log in a second time in the embedded browser. The new optional service Consultingwerk.Framework.Session.IWebSessionCookieService, with its default implementation WebSessionCookieService, receives the user name and password from Consultingwerk.Windows.Session.LoginForm after a successful login, performs a PASOE form based login through Consultingwerk.Framework.Http.FormBasedLoginHelper and caches the resulting JSESSIONID cookie. The AngularPreviewForm injects that cookie into the embedded Chromium browser using the new static helper Consultingwerk.CefSharpSupport.CookieHelper before navigating to the web application. The feature is opt-in: register the service in the services.xml of your application to activate it; without the registration the previous behavior of injecting credentials via JavaScript remains in place.

Rows of static temp-tables are now keyed by an INT64 instance id instead of a GUID

Classes that keep their temp-tables static now identify their rows with an INT64 instance id, assigned from a private static counter in the constructor, instead of a 36 character GUID. This avoids generating a GUID per instance, shrinks the rows and replaces the character index on the instance id by a faster integer index, which speeds up both object creation and the FIND / FOR EACH access by instance. Customer code is only affected where the instance id was previously exposed outside the class; in those places the GUID is kept or the change is documented in the class.

Fixed: FrameParser:GetFrameWidgets no longer fails with error 132 on duplicate variable definitions

Converting a frame from a program that defines the same variable name more than once - for example r_Rid coming from a repeatedly invoked include file inside internal procedures - no longer raises the error 'ttWidget already exists' (132). GetFrameWidgets now guards the creation of the widget temp-table record so that the first definition wins. No changes required in customer code.

New SmartFramework MCP server tool returns the WhereUsed information of a repository object master

The SmartFramework MCP server provides a new tool that returns all object masters containing a given object master as an instance. The object master is identified either by its ObjectMasterGuid or by its ObjectName, and for every hit the tool returns the object name and object master GUID of the containing object master together with the instance names under which it is placed. The response is built by the ABL procedure under Consultingwerk/SmartFrameworkMcpServer/ and converted with Consultingwerk.Framework.Toon.ToonConverter, so the output is returned in TOON format as a tabular array, consistent with the other repository tools of the server.

Fixed: DynamicTreeViewForm now repositions the detail panel data source to the selected tree node

The GUI for .NET rendering of repository tree view forms now evaluates the DataSource, KeyFields, KeyValues, ForeignFields and ForeignValues properties of the tree node detail spec and repositions or filters the data source of the rendered panel accordingly, matching the behaviour of the web front end. The same template is no longer re-rendered when only the key values change; the existing panel's data source is repositioned instead. No changes required in customer code as long as the tree node provider returns the detail spec key values.

Fixed: SmartBusinessEntityLookup no longer clears a just saved key value when the record is re-displayed

SmartBusinessEntityLookup:HandleForeignFieldValueChanged now ignores foreign field value changes that are raised while the data binding is re-displaying a record (guarded by BindingSourceHelper:IsBindingChangingValue, the same guard already used by FetchDataFromKeyValue and OnTextChanged). A lookup value entered before saving therefore stays visible after the save instead of being cleared by a re-validation with an empty foreign field value. No changes required in customer code.

Close confirmation in the CustomerExplorer and MainMenuForm is now only shown when child forms are open

The CustomerExplorer form of the SmartComponents demo and the MainMenuForm in Consultingwerk.Windows.Framework.Reference now check in OnFormClosing whether at least one MDI child form other than the start form, or a child form outside the MDI container, is open before the confirmation question (SmartMessage SFR:1) is asked. When nothing is open the main form closes without a prompt. Closing due to a Windows shutdown keeps its previous behaviour, and applications derived from these forms inherit the new behaviour without any code change.

PASOE Agent Telemetry timer no longer stops permanently after an unexpected OEManager exception

invokeJmxOperation in PasoeAgentTelemetryService now also catches RuntimeMBeanException and other unchecked exceptions and wraps them in a PasoeAgentTelemetryException, so a TelemetryError record is written instead of the exception escaping the scheduled task. Errors are additionally caught per ABL application and logged, and an unexpectedly terminating collector task is reported in pasoe-agent-telemetry.log. One failing ABL application no longer stops telemetry collection for the others, and a transient failure no longer kills the timer until the web application is restarted.

New Smart Telemetry Monitor: web dashboard for the PASOE Agent Telemetry data

The Smart Telemetry Monitor is a new Java web application (smart-telemetry-monitor.war) that is deployed into the PASOE Tomcat next to the PASOE Agent Telemetry collector and visualizes the NDJSON data it writes. It imports the files incrementally into an embedded SQLite database and serves an Angular front end with views for the ABL application, agents, sessions and sessions per agent, showing memory consumption, agent and session counts, request rates and reserve session waits over a selectable time range. Installation only requires copying the WAR into the webapps folder; the REST API under /api is documented and can also be used for own tooling.

Fixed: session StartTime in the PASOE Agent Telemetry output now uses the correct time zone offset sign

The collector previously wrote the session StartTime returned by OEManager unchanged, which carries the offset with an inverted sign (-02:00 instead of +02:00). The value is now parsed and re-formatted as ISO 8601 with the correct offset; unparseable values are written through unchanged as before. No changes required in customer code. Existing NDJSON files keep the old values; consumers such as the Smart Telemetry Monitor normalize them on import.

PASOE Agent Telemetry NDJSON output now supports file rotation and retention

The telemetry collector supports new optional settings in conf/smart-telemetry.properties - rotateEverySeconds, rotateAtBytes and keepFiles - which can be configured globally or per entry in ablapps[]. Rotated files carry a timestamp before the file extension, a rotation never splits a record, and rotated files beyond keepFiles are deleted automatically. Rotation is switched off by default, so existing installations behave exactly as before until the settings are added.

PASOE Agent Telemetry now collects session data on OpenEdge 12.2 via an automatic OEManager fallback

The PASOE Agent Telemetry web application now detects whether the OEManager AgentManager MBean offers the getAgentSessions operation. On OpenEdge 12.2, where that operation does not exist, the collector falls back to getAgents plus getSessionMetrics per agent and builds the same agents and sessions structure. NDJSON telemetry records are therefore written on 12.2 instances just as on 12.8 and 13.0. No configuration change is required.

SmartComponent Library prepared for OpenEdge 13.1

The SmartComponent Library now knows OpenEdge 13.1 as a release next to 12.2, 12.8 and 13.0. Consultingwerk/ProVersionEnum.cls has a new P131 constant and its ToDecimal method resolves 13.1 version strings, Consultingwerk/openedgeversion.i defines the new OpenEdge_13_1 preprocessor name together with all cumulative defines of the earlier releases, and the Business Entity Designer settings dialog offers 13.1, 13.1/32 and 13.1/64 in the OpenEdge version list. Code that tests the cumulative defines, for example the query builder predicate classes, continues to work unchanged because OpenEdge_13_0 remains set on 13.1. No changes are required in customer code; applications that maintain their own version lists or build configurations may want to add a 13.1 entry.

Client-side dataset cache added for the SmartBusinessEntityAdapter (CacheDatasets and CacheAge)

A new client-side, in-memory dataset cache is available in the Consultingwerk.Framework package: the IDatasetCacheService interface with the DatasetCacheService implementation, a session singleton resolved through the service container, which stores copies of datasets under a cache key together with an expiry time and an optional tag. The SmartBusinessEntityAdapter can use this cache through the two new properties CacheDatasets (logical, default FALSE) and CacheAge (integer, seconds, default 300): when caching is enabled, every fetch whose request arguments - entity, tables, queries, batch size and paging context - match an entry that is not older than CacheAge is served from the cache instead of the backend, while updates and explicit refreshes (F5, RefreshData, RefetchCurrentRow) always read from the backend and update the cache. Developers enable caching by setting the two properties on the data source, either in code or through the two new repository attributes CacheDatasets and CacheAge, which are rendered by the DataSourceRenderer; applications can discard the cache with IDatasetCacheService:ClearCache (), for example on logout. Caching is transparent for browsers, viewers and other data source consumers and is disabled by default, so existing applications are unaffected.

Fixed: Telemetry records of APSV and MCP server requests now contain the authenticated user name and domain name

Telemetry records written for APSV requests that authenticate with an auth key - in particular the requests of the SmartFramework MCP server - contained neither the user name nor the domain name, because the two places that populate these values (TelemetryService:BeginRequest from the client-principal and ServerSessionActivator:ActivateServerSession from a client context dataset) are not reached for such requests. The MCP authentication now forwards the authenticated user to the telemetry service after ValidateUser has succeeded, and the session context is completed with the login company resolved from the login company key, so that the user name and domain name are available to the telemetry record and to any other consumer of the session context. No changes required in customer code.

Fixed: Telemetry records now report the main service of a request instead of authentication or session activation helper calls

Telemetry records used to report the first service call of a PASOE request, which meant that authentication and session activation helper calls (for example UserBusinessEntity:ValidateUserPassword and the SmartLoginCompany cache query) were recorded as the service name, service request and prepareQuery of the record instead of the service that actually performed the work. ITelemetryService now offers ResetServiceRequest (), which clears the service name, service request, prepareQuery and queries of the current record; the framework calls it once session activation or authentication is complete, so the first real service call afterwards is the one that gets recorded. This applies to both REST and web requests via RestServerSessionActivator:ActivateServerSession and to MCP server requests after the authentication. MCP procedures whose work does not go through the ServiceInterface set their service request explicitly through a helper on SmartFrameworkMcpServerHelper. No changes required in customer code.

Authentication now calls the User Business Entity directly on the server instead of through the ServiceInterface

Consultingwerk.SmartFramework.Authentication.AuthenticationService:ValidateUser used to invoke UserBusinessEntity:ValidateUserPassword and CheckLoginCompanyAccess through ServiceInterface:InvokeTask when running on the server, while the user record itself was fetched directly through ServiceManager:GetBusinessService. As a result, request authorization was executed for a session that was not authenticated yet, and the authentication call was recorded as the service request of the telemetry record. On the server these tasks are now invoked directly on the Business Entity obtained from the ServiceManager, so authentication is treated as an infrastructure call that neither passes request authorization nor overwrites the telemetry service request. The ServiceAdapter path used by clients is unchanged. Applications that rely on authorization rules explicitly permitting ValidateUserPassword for anonymous sessions can remove those rules; no other changes are required in customer code.

Business Entity Designer now maintains Business Entity Descriptor and Table Descriptor properties

The Business Entity Designer now provides dedicated editors for the Business Entity Descriptor properties on the entity node and the Table Descriptor properties (the @BusinessEntityTable and @BusinessEntityView annotation attributes) on the temp-table nodes. The values are stored in the .bedgm model as custom properties named BusinessEntityDescriptor and TableDescriptor, each holding a JSON document whose keys match the annotation attributes, so they survive regeneration and are versioned with the design. The generator emits the corresponding annotations into the Business Entity class and imports existing hand-written annotations into the model instead of overwriting them, and the designer validates field lists and the placeholders of DescriptionSubstitute. The JSON structure of both properties is documented in a Markdown file next to the ABL sources.

New SmartCommentControl for maintaining rich text comments on any record

The new GUI for .NET user control Consultingwerk.Windows.Framework.System.SmartCommentControl provides the missing user interface for record comments, which are stored as RTF in the CommentData CLOB of the SmartAttachment table. Like the SmartAttachmentControl, the control is placed on a form in the Visual Designer and linked to the data source of the record through its SmartDataSource property; it lists the comments of the current record, offers add, edit, save, undo and delete, comment role selection and a proposed but editable comment title, and edits the text in a Telerik RadRichTextEditor with bold, italic, underline, font face, font size, font color and image support. The server side logic is implemented in the new Consultingwerk.SmartFramework.System.CommentDatasetController, which loads the comment text through AttachmentBusinessEntity:GetLargeObjects only for the selected comment. The SmartAttachmentControl now filters on AttachmentRoleGUID so comment rows no longer appear in the attachment list, and the Comments tab of the customer detail form in the demo application shows the control in use. No database schema change and no changes in customer code are required.

SmartAttachmentControl and SmartCommentControl can now be used on repository based Desktop forms

The attachments control (Consultingwerk.Windows.Framework.System.SmartAttachmentControl) and the comments control (SmartCommentControl) are no longer limited to static forms in the Visual Designer. New repository object types allow both controls to be placed on a MetaForm page or tab, and a DataSource link from the control instance to the MetaDataSource of the record is mapped to the SmartDataSource property of the control during rendering. The Desktop DynamicFormRenderingService instantiates and disposes the controls with the same lifecycle handling as the static controls, and the Object Master Designer offers palette entries, component type images and property sheets for the new object types. A dynamic form can therefore show the attachments and comments of the current record of a MetaViewer or MetaGrid without any static code.

SmartFramework MCP server no longer unconditionally overwrites the Business Entity registration in SmartTable

When the Business Entity Designer MCP server creates or regenerates a Business Entity, the registration in the SmartTable record is now only written when it is not set yet or when the developer explicitly requests it. The maintenance Business Entity registration and the query Business Entity registration can be controlled independently. In addition, a dedicated MCP tool is available to update either registration for a given SmartTable record. Existing registrations that were deliberately set are therefore preserved during regeneration.

SmartDB database triggers converted to lower case ABL keywords

The remaining 67 database trigger procedures in ABL/src/SmartDBtrgs/ have been converted to lower case ABL keywords and now carry the @lowercase. annotation, in line with the code formatting rules of the SmartComponent Library. The conversion was performed with the convert-lowercase tool and is behaviour neutral - only keyword casing and the annotation changed. No changes are required in customer code.

Logic of the SmartFramework MCP server legacy GUI procedures moved into Business Tasks

The application logic of the MCP server procedures in Consultingwerk/SmartFrameworkMcpServer/legacygui/ (frame to MetaFrame conversion, browse to MetaGrid conversion and the frame and browse name lookups) has been moved into a Business Task in the Consultingwerk.Studio.LegacyGuiMigration namespace. The procedures now only implement the service interface - authentication, request logging, telemetry and JSON response building - and call a single Business Task method that returns a strong-typed result object. The conversion logic is therefore reusable from the Desktop client, the web and unit tests, and testable independently of the MCP transport. The signatures and the behaviour of the existing MCP tools are unchanged, so no changes are required in customer code.

Business Entity Designer now asks before removing manual AssignSkipDictionary or AssignSkipList code

When the Business Entity Designer updates the DataAccess constructor, it now compares the existing AssignSkipDictionary:Add statements and any legacy AssignSkipList assignment with the design and asks for confirmation before anything is removed. Fields or entries that are only added no longer raise a question, and declining leaves the whole AssignSkipDictionary section of the constructor untouched. AssignSkipDictionaryParser2 and ListAssignSkipDictionaryEntry2 now also detect the AssignSkipList assignment, BusinessEntityGenerator gained GetAssignSkipDictionaryRemovals, and RefactorSession2:RemoveNodeRange removes a statement together with its line so no whitespace-only lines remain. In silent mode (batch generator, MCP server) the question is logged through the LogManager and the update proceeds. No changes required in customer code.

New NdjsonLoggingStream writes structured NDJSON log records for log aggregation tools

The new class Consultingwerk.Util.LoggingStream.NdjsonLoggingStream inherits from the abstract LoggingStream base class and writes exactly one JSON object per logging call to a UTF-8 file (NDJSON / JSON Lines), so that log files can be processed directly by tools such as Elasticsearch, Loki, Splunk or jq. Constructors are available for truncating and for append mode, and every record carries a standard set of properties (timestamp, logEntryType, loggingLevel, loggingLevelName, recordType and message), the PASOE request context properties when available, and the properties of the additional Context JsonObject the application can populate. Record type specific content is written for messages, errors including the inner exception chain and custom AppError properties, JSON data, buffers, object properties, stack traces and the PROPATH, and the custom log entry type filtering behaves exactly as in FileLoggingStream. To capture the substitution values of formatted messages, the LoggingStream base class gained the protected hook WriteFormattedMessageInternal, whose default implementation preserves the output of all existing stream implementations - no changes are required in customer code.

SmartFramework MCP server supports Business Entity Designer custom properties (names, values, update)

The SmartFramework MCP server gains tools to list the custom property names available for a Business Entity Designer scope - Business Entity, table, field, index or relation - including the names and value lists contributed by the registered Designer plugins, to read the values stored in the .bedgm model for a given scope and scope name, and to create, update or remove a single value. The tools reuse the Business Entity Designer plugin infrastructure (GetCustomPropertyNamesEventArgs and GetCustomPropertyValuesEventArgs) rather than duplicating the property lists, and Markdown files versioned with the ABL sources document the structure of properties whose value is structured, such as the JSON of BusinessEntityDescriptor and TableDescriptor. An AI assistant working through the MCP server can therefore discover, read and maintain custom properties instead of editing the model file directly. The existing create_businessentity and regenerate_business_entity tools are unchanged and custom property values survive a regeneration.

Fixed: User table statistics monitor no longer fails when an OpenEdge 11.7 database is connected

The RequestUserTableStatsMonitor service failed to load with error 1494 (Could not find file _UserLobStat) when the PASOE instance connected a database still running under OpenEdge 11.7, because the compiled r-code of Consultingwerk.OERA.TableStatistics.UserTableStats carried a static schema reference to the _UserLobStat VST introduced in OpenEdge 12.0. The LOB statistics access has been separated out so that it is only used when the connected database actually provides the VST, and is silently skipped otherwise. Table and index statistics are collected as before; LOB statistics are simply not available for such databases. No changes required in customer code. Reported via SCLSUP-759.

Checkbox selection added to the TreeView, including data binding and server side event handler events

The TreeView component can now display an optional checkbox column, allowing nodes to be checked and unchecked independently of the currently highlighted node. The feature is controlled by the new MetaTreeView design attributes Checkboxes, CheckedNodes and CheckedNodesDelimiter, where CheckedNodes binds the delimited list of checked node key values to a field of the hosting viewer's data source in both directions, and checked states survive lazy loading of child nodes. Two new repository events, NodeChecked and NodeUnchecked, are raised per node and are handled through the new parameter interfaces Consultingwerk.CommonUi.INodeCheckedEventHandlerParameter and INodeUncheckedEventHandlerParameter, so a server side event handler can react to or reject a change. Checkboxes are off by default, so existing TreeView instances are unaffected; the extended Customer details tree view demo shows the new functionality.

OpenEdge ProTools can now be launched directly from the SessionInfoForm in developer mode

Consultingwerk.Windows.Session.SessionInfoForm can now show a row of icon-only buttons for a selection of the OpenEdge ProTools (Config info, DB List, OS Prompt, Editor, Procedures, Propath, Run, Session, Windows Info, Service Parameter Maintenance and AppServer Information), each with the tool name as its tooltip and an overflow drop-down when the form is too narrow to show them all. The buttons are only added when the new FrameworkSettings:DeveloperMode switch is enabled, which follows the pattern of FrameworkSettings:DebugMode and is set when SESSION:PARAMETER contains DeveloperMode. The buttons are supplied by an optional service resolved through get-service.i, modelled on Consultingwerk.Windows.Util.Forms.IMessageFormButtonProvider; the SmartComponent Library ships the ProTools implementation and registers it in Consultingwerk/Studio/services_studio.xml, and applications can register their own implementation in their services.xml. The required icons ship as transparent PNG images below Consultingwerk/Windows/Session/Images/ and are loaded through Consultingwerk.Util.ImageHelper:Load.

Release notes download on Windows now uses the .NET HTTP client, removing the OpenEdge certificate store requirement

Consultingwerk.Studio.ReleaseNotes.ReleaseNotesDownloader now downloads the Confluence release notes through the .NET Framework HTTP client when running in a GUI for .NET session on Windows, guarded by &if defined (DotNetAccessible). Because the .NET client uses the Windows certificate store, the Business Entity Designer start page no longer shows a TLS error when the Atlassian root certificate or a corporate TLS inspection certificate has not been imported into the OpenEdge certificate store in %DLC%\certs. The OpenEdge HTTP client remains as the fallback, so ReleaseNotesProxyBusinessTask on PASOE continues to work on Linux and Windows, and the output contract of DownloadReleaseNotes () is unchanged, meaning download-rss.p and ReleaseNotesControl are unaffected. .NET exceptions are mapped into the existing error handling so download errors are still reported in the release notes panel; no changes are required in customer code.

Fixed: MessageProvider no longer reloads the entire SmartMessage table on every message cache miss

With the static property MessageBusinessEntity:CacheMessagesAtStartup set to true, the MessageProvider constructed a new unmanaged MessageBusinessEntity on every message cache miss, so the whole SmartMessage table was reloaded into an instance scoped cache that was discarded again immediately. The MessageProvider now creates one dedicated unmanaged instance lazily and reuses it for its whole lifetime, which restores the once-per-session cost of the eager cache and also removes the per-lookup construction of a Business Entity and DataAccess when the flag is off. Customers who set CacheMessagesAtStartup = false as a workaround can revert that setting; no other changes required in customer code.

REST resource registration performs the classpath discovery once per session instead of three times

RestResourceService now performs the discovery of annotated classes (reading the classpath, walking the directories for .annotations files, parsing them and resolving the classes) once per instance and reuses the result for all three registration passes, where GetClassNames previously repeated the whole scan for each pass. This noticeably shortens the ABL session cold start of a PASOE instance whenever no REST resources cache file is available, for example in the first session after a deployment, in development workspaces and in unit tests. In addition, the message that a class has an .annotations file but does not implement ISupportsRestAddress or ISupportsRestMethods is now logged at the Extended logging level, since it is the normal case for framework classes carrying other annotations. No changes required in customer code.

Consultingwerk branded class templates now generate classes that include Consultingwerk/products.i

The 36 class, interface and enum templates in Consultingwerk/Templates that did not yet do so now emit {Consultingwerk/products.i} directly below the block-level on error undo, throw. statement, matching the placement already used by datasetcontroller.template. Without the include, generated classes lost the {&TRAN} macro (so translation attributes silently disappeared and TranslationAttributeTest failed) and had no access to the cumulative OpenEdge version defines from Consultingwerk/openedgeversion.i. The product neutral templates in Consultingwerk/BusinessEntityDesigner/Generator/Templates are deliberately unchanged, so code generated for projects that do not ship the SmartComponent Library still compiles. Developers using the TemplateFolder setting Consultingwerk/Templates should regenerate affected classes to pick up the include; no other changes are required in customer code.

Fixed: Business Entity regeneration through the MCP server no longer aborts with error 15809

Regenerating a Business Entity through the SmartFramework MCP server failed with "You can only use the .NET event loop in a GUI application (15809)" for every Business Entity whose DataAccess class carries no @AttachDataSourcesStart / @AttachDataSourcesEnd annotation pair, because the generator reported that recoverable condition through a GUI message box. The warnings in BusinessEntityGenerator now honour SilentMode and the multi-session agent check and are written to the log instead, so generation continues as it does in the Designer. This also affects DataAccess classes whose AttachDataSources method is maintained by hand. No changes required in customer code.

The .NET assemblies are now provided as a separate ESD product

The .NET assemblies (including CefSharp and the .NET Core assemblies) are no longer part of the weekly SmartComponent Library release in the ESD. They change much less frequently than the ABL source code, so they are now provided in the separate ESD product SmartComponent Library Assemblies. We create a new release there whenever the assemblies change. The release name Assemblies @ <build number> contains the build number of the corresponding weekly release.

The files Assemblies/assemblies.xml and Assemblies/assemblies.config are now included in the source code ZIP files of every weekly release. They show which assembly versions the release requires. When these versions change, download the latest release of the SmartComponent Library Assemblies product and update the Assemblies folder of your project. Otherwise the ABL code may fail to compile.

Customers with an active maintenance agreement have access to both ESD products. If the SmartComponent Library Assemblies product is not available in your ESD account, please contact us.

StringHelper converts text between plain text, RTF, Markdown and HTML in all twelve directions

Consultingwerk.Util.StringHelper gains conversion methods between plain text, RTF, Markdown and HTML - ConvertRtfToText, ConvertRtfToHtml, ConvertHtmlToRtf, ConvertMarkdownToHtml and the other nine - plus the generic ConvertText method taking the new Consultingwerk.Util.TextFormatEnum, and the IsRtf test. The conversion is pure ABL and LONGCHAR based, so it runs in the backend on Linux PASOE; it is implemented by one reader and one writer per format over the shared TextDocument model in the new Consultingwerk.Util.DocumentConverter package, and carries paragraphs, character formatting, fonts, sizes and colours, paragraph alignment and indentation, bullet and numbered lists, tables, hyperlinks and embedded PNG and JPEG images as far as the target format can express them. Conversions are stable from the second pass on, so content stored as RTF can be handed to a web front end as HTML and taken back as RTF repeatedly without drift - a developer calls ConvertRtfToHtml in the Business Task or Business Entity method that returns the value and ConvertHtmlToRtf before storing it again. The Convert methods and IsRtf are compiled only when the DocumentConverter switch of Consultingwerk/products.i is set.

Fixed: Counting records for ObjectMasterBusinessEntity child tables no longer fails to prepare the query

Counting records for the eSmartPage, eSmartObjectInstance and eSmartLink child tables of ObjectMasterBusinessEntity failed with "Unable to prepare query" whenever the request supplied an empty query string, because the resulting query had no buffer phrase. ObjectMasterDataAccess now builds a complete query in that case, so the request returns the record counts as it already did for other entities. This unblocks the record counts of the Pages, Instances and Links tabs in the Angular Object Master Designer. No changes required in customer code.

Count requests no longer perform a wasted record fetch for every leaf row

CountRecordsBusinessTask now resolves field values only when at least one child row refers to the current row, instead of doing so for leaf rows as well. Previously every leaf row of a count request triggered a FetchData call whose record was never used, which slowed down batched count requests such as those sent by the tab folder of the web Object Master Designer and could fail an entire count request because of an unnecessary fetch. No changes required in customer code.

New RefreshTreeViewUiAction reloads a tree view from a server-side event handler

The new class Consultingwerk.CommonUi.RefreshTreeViewUiAction lets a server-side event handler make a tree view reload its structure from the ISmartTreeNodeProvider - unlike the existing RefreshNode, which only re-reads the values of a single node. A handler adds the action to the UiActions list of the UiControl it returns, optionally naming the MetaTreeView instance, the node to select afterwards (NodeKey) and additional nodes to open (ExpandNodes, a pipe delimited list of node key tokens), which is how a newly created record below a collapsed parent is made reachable. Nodes that were expanded before the refresh, the selection and the checked nodes of a tree view in checkbox mode all survive the reload, and both a tree view rendered inside a MetaViewer and one placed directly on a MetaForm are supported. The action is returned by code, so no repository meta data changes are required; the SmartComponents NG front end support is tracked in SCLNG-1794.

Business Entity Designer relation getters are now generated on the server, and the relation custom properties are documented

The BusinessEntityRelationsPlugin has been split into an abstract base class, a GUI plugin and a new server plugin (BusinessEntityRelationsServerPlugin), both registered in .BusinessEntityDesignerSettings.xml. As a result the generated relation navigation methods are now also produced by headless and MCP based generation runs, where they were previously missing. In addition, the open-ended relation_<n> temp-table custom properties are now documented under Consultingwerk/BusinessEntityDesigner/CustomProperties, including the JSON structure of RelationDesignAttributes and the pairing rule of the ForeignFields list. No changes required in customer code.

Pure-ABL ProparseApi is now the default IProparseApi implementation where .NET is not accessible

The InterfaceGenerator, the Adm2SmartDataFieldPreProcessor, the Business Entity Designer batch procedures and convert-lowercase resolved IProparseApi with the .NET based ProparseDotNetApi as their default implementation and therefore did not compile without .NET. The default is now the pure-ABL ProparseAblApi whenever DotNetAccessible is not defined, so these sources compile and run on Linux PASOE and in TTY sessions without assemblies. The GUI behaviour is unchanged and no changes are required in customer code.

NodeRefactorException now compiles without .NET, enabling the ProparseApi based LegacyGuiMigration parsers on the server

The .NET USING statements, the Node property and the JPNode constructor of Consultingwerk.Studio.LegacyGuiMigration.NodeRefactorException are now guarded with DotNetAccessible, while the constructor taking the pure-ABL INode stays available everywhere. As a result DisplayToAssignNodeAction2, ValidationMessageNodeAction2, UpdateEditingParser2 and LeaveTriggerParser2 compile in TTY mode without assemblies and can be used on Linux PASOE. No changes required in customer code.

Fixed: SessionInfoProvider now compiles on Windows in sessions without .NET

The Windows version block of Consultingwerk/Util/SessionInfo/SessionInfoProvider.cls was guarded by OPSYS only, although it uses System.Environment:OSVersion and the Registry class, so a compile on Windows in TTY mode or without assemblies failed with "Unknown Field or Variable name - Registry. (201)" and took RestResourcesJsonReader, SupportSnapshotProvider, SessionInfoWebHandler and the MCP tool get-session-info.p with it. The guard now also tests DotNetAccessible. No changes required in customer code.

.NET-free implementations provided for helper members that previously required DotNetAccessible

Several helper members existed only inside DotNetAccessible blocks and were therefore unavailable on Linux PASOE: ClassHelper:GetClassNames and GetInterfaces, FileHelper:SubstituteSpecialFolderPath and EnsureFileNameCase, DataTypeHelper:CharacterToByteArray, ResourceFileHelper:IsLocalizable, WidgetHelper:Count and the parameterized constructor and GetClassMembers of the ClassAnnotationParser. Where a server side implementation is meaningful it is now provided in an &else branch - for example class discovery through the file system and the PROPATH for GetClassNames - so the members and the unit tests covering them can be used without .NET; members that remain .NET only are documented as such. The GUI behaviour is unchanged and no changes are required in customer code.

ClassAnnotationParser now works without .NET by using the IProparseApi abstraction

Consultingwerk.Studio.ClassAnnotationParser has been rewritten to parse class and class member annotations through Consultingwerk.Studio.ProparseApi.IProparseApi instead of the .NET based proparse classes. The implementation is resolved through Consultingwerk/get-service.i, defaulting to ProparseDotNetApi where .NET is accessible and to the pure ABL ProparseAblApi otherwise. As a result the ClassAnnotationParser now compiles and runs on Linux PASOE and in the ABL Agent code base, and SmartUnit:GetAnnotationParser and the ExtractClassAnnotationsJob no longer need to fall back to the XrefClassAnnotationParser. Customer code using the ClassAnnotationParser continues to work unchanged; no DotNetAccessible guards are required around it any longer.

Fixed: ClassHelper:GetClassNamesNoDotNet no longer skips classes whose r-code merely contains the text "System."

Consultingwerk.Util.ClassHelper:GetClassNamesNoDotNet and GetInterfacesNoDotNet used a plain substring search for "System." in the r-code to exclude .NET dependent types. This silently skipped every class whose r-code contained that text for other reasons, in particular all classes in a package named System, such as the Business Entities of Consultingwerk.SmartFramework.System, leading to incomplete class and service discovery in sessions without .NET. The detection of .NET dependencies has been corrected so that these classes are returned again. No changes required in customer code.