Skip to content

Releases: serenity-is/Serenity

10.0.1

24 Nov 14:45

Choose a tag to compare

Features

  • First .NET 10 version. You'll need to install Visual Studio 2026 and .NET 10 SDK.
  • Please stay at 9.2.x versions if you still need to use Visual Studio 2022 and .NET 8.
  • Strict Content-Security-Policy (CSP) is enabled in StartSharp template by default.
  • AddCspDirective overloads for ControllerBase and HttpContext
  • Instead of using sleek-vars.rtl sleek-vars.ltr etc. change the values of --l, --r variables based on rtl. Increase number of supported columns to 100 from 50 which should be enough for most cases.
  • Add styleNonce option to SleekGrid constructor support more strict CSP directives. If not passed, it will be looked up from a meta element with csp-nonce name, or style/script with nonce value in document head.
  • Replace inline style attributes to potentially support stricter CSP directives. Currently only CKEditor 4 is an issue as it requires unsafe-inline.
  • Configured HtmlNoteContentEditor and HtmlReportContentEditor to use Tiptap instead of CKEditor (StartSharp). See tiptap-init.ts file in latest template. Tiptap usage is currently opt-in. CKEditor support will be removed in a future version as it is out-of-date and is not compatible with strict CSP.
  • Add helpers to add / get CSP directives, both from the layout and per specific pages (like emailclient page which uses CKEditor 4 that requires unsafe-inline)
  • New useUpdatableComputed helper in domwise to create a factory for computed signals that can be manually updated as a batch (by internally incrementing a counter signal). This may be useful for computed signals that depend not only on other signals, but externally changing state.

Bugfixes

  • Fix potential issue with SlickFormatting.treeToggle when formatter returns a string, and enableHtmlRendering is false. Update the default comment in FormatterContext.enableHtmlRendering
  • Fix remaining discovered CSP related issues in sample pages

9.1.3

14 Nov 19:57

Choose a tag to compare

  • @serenity-is/domwise is our new library to create DOM elements with full TypeScript support. It is primarily based on jsx-dom with integrated signal support via @preact/signals-core and some extra types / ideas from ryansolid/dom-expressions (SolidJS) and lusito/tsx-dom. @serenity-is/domwise also exports signal functions like signal, computed, effect etc. from @preact/signals-core and supports signals as attribute values and element children, and reactively updates the attributes and dom nodes when signal values change. Please remove jsx-dom from your package.json, and set the jsxImportSource to @serenity-is/domwise. There are a few differences between jsx-dom and domwise. The HTML element attributes are lowercased to match the actual HTML attribute casing, e.g., readonly instead of readOnly, for instead of htmlFor. We aliased some like tabIndex, htmlFor, maxLength etc. for easier transition. This should make it easier to copy/paste actual HTML code to our .tsx files, e.g., from a Bootstrap sample. For compatibility, event handlers are left as camelCase, e.g., onClick.
  • The layout system for SleekGrid is completely rewritten, and we now introduce EnhancedLayout (StartSharp), which is an improved and feature-complete version of previously available (but unused) FrozenLayout. It supports pinning columns to the left (start) or right (end) and frozen columns at the top or bottom. EnhancedLayout is enabled by default for all grids in StartSharp, though pinning / frozen rows are opt-in via column menu / options. If you were using FrozenLayout in some of your grids (by overriding getSlickOptions), it is recommended to remove it.
  • Columns now have a functional dropdown menu with actions to hide columns, show column picker, reset columns, edit column filter, change sort order, move the column to the left or right, pin columns (EnhancedLayout), auto-size the column (AutoColumnWidthMixin), group by the column (DraggableGroupingMixin), and set the Summary/Aggregate types (CustomSummaryMixin).
  • Automatic Registration for Grid Mixins/Plugins (StartSharp): All the available grid plugins / mixins like HeaderMenuPlugin, AutoColumnWidthMixin, CustomSummaryMixin, DraggableGroupingMixin and HeaderFiltersMixin now provide an option to automatically register with all grids in the application. It is also possible to limit the registration to a subset of the grids via a predicate. Auto-registration is configured in StartSharp via Modules/Common/script-init/autoregister-init.ts file where you may customize the auto-registration process and override options for the auto-registered instance.
  • HeaderFiltersMixin provides an option (showButtonWhenNotFiltered) to hide the filter button when the column is not filtered. This is useful to save space for the column header itself.
  • DraggableGroupingMixin has an option named showPanelWhenNoGroups that, if set to false, hides the grouping bar (one with text Drag a column here...) when there are no grouped columns.
  • CustomSummaryMixin offers an option named showFooterWhenNoSummaries that, if set to false, hides the grid footer when there are currently no columns with summaries. It also shows indicator symbols for the current aggregate type.
  • Renamed [ScriptSkip] attribute to [TransformIgnore] attribute to better match the intent, e.g., ignoring the class or property during Sergen/Pro.Coder transforms from C# to TypeScript. ScriptSkip still exists but is deprecated. The old name felt a bit like 'skip this on the client/script side'.
  • Renamed [Ignore] attribute to IgnoreUIField to better match the intent, e.g., ignoring the generation of column / form fields for that property. Ignore attribute still exists but is deprecated. The old name was not clear enough.
  • Renamed IgnoreNameAttribute to SkipNameCheckAttribute to better match the intent. IgnoreName attribute still exists but is deprecated.
  • [OneWay] attribute is also obsolete; use the [SkipOnSave] attribute. There is now a [SkipOnLoad] attribute which does for loading what [OneWay]/[SkipOnSave] does for saving. We also now have an [Unbound] attribute, which when placed on a column property, will cause the column to have no field, and act like a mix of [SkipOnSave, SkipOnLoad, SkipNameCheck].
  • Renamed Grid (@serenity-is/sleekgrid) to SleekGrid to avoid mix-ups with DataGrid, EntityGrid and other grid types.
  • New Attributes namespace which works similarly to the @Decorators namespace for [Symbol.typeInfo] style type registration, e.g., [Attributes.panel()] instead of [new PanelAttribute()]
  • The FilterableAttribute which used to control advanced filtering on grids via a bottom filter bar and an advanced filter dialog is renamed to AdvancedFilteringAttribute which you may use via Attributes.advancedFiltering().
  • When there is no active advanced filter, the filter bar will no longer be shown to save space. To make it possible to edit an advanced filter when the filter bar is hidden, we added a tool button next to the column picker. The filter bar is also moved to the top of the grid. This will make it easier to identify when a grid has an advanced filter.
  • The getColumns method is deprecated (DataGrid/EntityGrid). We had a protected getColumns() method in DataGrid subclasses that is used to create the initial column set for a grid, but because its name matched the SleekGrid's getColumns() method that returned the current set of visible columns in the grid, sometimes users tried to call this method to get the current columns, instead of dataGrid.sleekGrid.getColumns(). Please override protected createColumns() method instead which better matches the intent. To access currently visible columns for a data/entity grid, you may use .columns property, or .sleekGrid.getColumns(). To access all the columns (including invisible ones, not necessarily matching the visible order) use .allColumns property or .sleekGrid.getAllColumns().
  • For compatibility with jQuery, we previously chose to set style.display to none when an element is hidden via Fluent.toggle methods. We now decided to use the hidden attribute which applies to all element types, and actually hides the element even if the style.display property is overridden by a Bootstrap class like d-block. Fluent tries to handle this transition gracefully, but it is recommended to update the logic in your own files.
  • SleekGrid now has a better column dragging system that also works on touch devices.
  • Rewrote the layout system of the SleekGrid from the ground up. It now uses a CSS Grid layout for the main panels / viewport.
  • SleekGrid is now able to handle dynamic changes of pinned columns and frozen rows. It also handles them responsively so that when the viewport gets small (e.g., on mobile devices) or when there are not enough data rows, the number of pinned columns and frozen rows is temporarily reduced to make the scrollable area visible.
  • Note that SleekGrid that was hosted as a submodule inside Serenity repository, is now embedded as a sub-tree. If you are using Serenity as a submodule, you may need to rename / delete Serenity/packages/sleekgrid folder before pulling latest changes.
  • To avoid direct dependency on SleekGrid and RemoteView classes, we now have interface versions of these types, ISleekGrid and IRemoteView. This may affect you if you referenced one of these types directly.
  • SleekGrid now has an improved and more secure HTML sanitizer, based on DOMParser. Even though we enable DOMPurify in our application templates instead of this sanitizer, the built-in sanitizer should be sufficient for most cases. The old regex-based basic sanitizer could fail in some complex cases. @serenity-is/corelib now also has a sanitizeHtml function that uses SleekGrid's configured one if available, DOMPurify or its own DOMParser-based sanitizer. We recommend using this function where you need HTML sanitization for user-provided content (unless you directly reference DOMPurify).
  • Strings Returned From Formatters Are Assumed To Be Text (**[Breaking Change]**) as gridDefaults.enableHtmlRendering is now false by default. This means strings returned from formatters are assumed to be text, not raw HTML. You should convert those formatters to return HTML elements (via domwise etc). Note that when this flag is false (default now), the ctx.escape() function will return strings as is and will not HTML-encode them, as it would otherwise result in double HTML escaping.
    If you want to revert to the previous behavior (not recommended), set gridDefaults.enableHtmlRendering = true in ScriptInit.ts etc.
  • Added a MVC:AsNamespace option to sergen.json which causes a .MVC namespace suffix to be generated instead of an MVC class. When enabled, the ESM helper class will also be generated under this namespace, e.g., RootNamespace.MVC. This should reduce confusion when a namespace like Serenity.Extensions is added to global usings as it also has its own MVC helper. The default is false for now, as it would be a problem for ESM. references, as they would need to be written as MVC.ESM. or an alias would need to be assigned in the project file like <Using Include="$(MSBuildProjectName).MVC.ESM" Alias="ESM" />. New projects have this alias defined by default. The new defaults@9.0.0 in sergen.json can be used instead of defaults@6.6.0 to enable this flag by default (new projects will also use defaults@9.0.0).
  • Added VSIX support for Visual Studio 2026
  • Added comments to HeaderFiltersPlugin options. Added a getFilterText option to override the displayed value. Pass 'header-filter' as purpose to formatters. Allow passing more options through the mix...
Read more

9.0.0

10 Oct 09:05

Choose a tag to compare

  • Type registration via decorators (e.g., Decorators.registerClass, Decorators.registerEditor, etc.) is now deprecated (it still works but is not recommended):

    import { Decorators, Widget } from "@serenity-is/corelib";
    
    @Decorators.registerClass("MyProject")
    export class MyType extends Widget<any> {
    }

    Instead, use a static [Symbol.typeInfo] property declaration:

    import { Widget } from "@serenity-is/corelib";
    
    export class MyType extends Widget<any> {
        static [Symbol.typeInfo] = 
            this.registerClass("MyProject.MyModule.MyType");
    }

    This new approach offers several advantages over decorators. Most importantly, decorator information is not emitted by TypeScript in declaration files (e.g., .d.ts), making it difficult or impossible to identify registration names for referenced project/npm package types.

    Another reason for this change is a longstanding bug in esbuild (see issue) with decorators and property initializers, which currently only has a workaround by using experimentalDecorators: true in tsconfig.json.

    The new registration methods also support passing interfaces or attributes as an array in the second argument. For example, to set @Decorators.panel(true) on a class, you can do:

    import { Widget, PanelAttribute } from "@serenity-is/corelib";
    
    export class MyType extends Widget<any> {
        static [Symbol.typeInfo] = 
            this.registerClass("MyProject.MyModule.MyType", 
                [new PanelAttribute(true)]);
    }

    Note: When using this new registration method, TypeScript will not allow any decorators on the containing type, as the this expression is referenced in a static field initializer. If you need to use third-party decorators, you can use an alternative registration style:

    import { Widget, classTypeInfo, registerType } from "@serenity-is/corelib";
    
    @someCustomDecorator("test")
    export class MyType extends Widget<any> {
        static [Symbol.typeInfo] = 
            classTypeInfo("MyProject.MyModule.MyType"); 
        static { registerType(this); }
    }

    This is equivalent to this.registerType, as the registerType static method in Widget calls classTypeInfo and registerType internally.

    This style is also useful for formatter registration, as formatters typically do not have a base type and cannot simply call this.registerType like widget subclasses:

    export class MyFormatter implements Formatter {
        static [Symbol.typeInfo] = 
            formatterTypeInfo("MyProject.MyModule.MyFormatter"); 
        static { registerType(this); }
    }

    For consistency, you may also choose to extend the new FormatterBase class:

    export class MyFormatter extends FormatterBase implements Formatter {
        static [Symbol.typeInfo] = 
            this.registerFormatter("MyProject.MyModule.MyFormatter");
    }

    For all registration styles, you can now pass only the namespace ending with a dot (the enclosing type name will be auto-appended):

    import { Widget } from "@serenity-is/corelib";
    
    export class MyType extends Widget<any> {
        static [Symbol.typeInfo] = this.registerClass("MyProject.MyModule.");
    }

    Sergen / Serenity.Pro.Coder now also generates namespace constants under the Modules/ServerTypes/Namespaces.ts file, so you can use them to avoid typos:

    import { Widget } from "@serenity-is/corelib";
    import { nsMyModule } from "../../ServerTypes/Namespaces";
    
    export class MyType extends Widget<any> {
        static [Symbol.typeInfo] = this.registerClass(nsMyModule);
    }

    We hope this will reduce mistakes when renaming classes or using a namespace with mismatched casing.

  • Added an EditLink function that can be used instead of SlickHelpers.itemLink with JSX elements. The DataGrid also has an EditLink arrow function for use in formatters.

  • The row type itself is now used as the base row type if a row type is passed to the PropertyItemProvider.

  • Imports generated by ServerTypingsGenerator are now ordered and organized.

  • You can now pass formatterType by reference in PropertyItem.

  • Added a value argument to the Validator.optional method, allowing validation methods to be called without an element—just a value—when desired.

  • Adjusted the Validator's onfocusout method: if a required input is cleared and loses focus, it is still validated if it has a "required" rule. Otherwise, errors were not shown until the form is saved.

  • Introduced a new Inline Editing sample in the Grid Editor (StartSharp).

  • Added new options and improved features in GridEditController (StartSharp):

    • New getPropertyItem option to optionally override the column item.
    • The bulkSaveHandler option now works.
    • The saveHandler callback receives an args argument with a defaultHandler property, allowing you to call the default save handler when needed.
  • Splitted WizardDialog's renderContents method into renderButtons, renderCancelButton, renderBackButton, renderNextButton etc. to make it easier to modify/inject content (StartSharp)