- Add more service collection extensions to simplify service registration in Startup.cs:
AddClamAVUploadScanner,AddElevationHandler,AddEmailSender,AddPasswordStrengthValidator,AddHttpContextItemsAccessor,AddCssBundling,AddCssAndScriptBundling,AddScriptBundling,AddLocalTextInitializerand anAddUploadStorageoverload. AddAddBackgroundJobs,AddPuppeteerHtmlToPdfandAddSecureUploadFileResponder(StartSharp). TranslationRepositorynow usesILocalTextInitializerin Serene instead of the staticInitializeLocalTextsmethod in Startup.- Apply RTL related changes for SleekGrid from sleekgrid PR #16, and adjust
slick.base.cssso that it works properly in RTL mode, including in the Pro theme which runs RTL CSS. Add a basic RTL SleekGrid sample, and manually apply the patch from unmerged SortableJS PR #2368 for RTL support. - Correct RTL drag constraints in SleekGrid by swapping shrink/stretch leeways (#7420).
- Also generate a namespace constant for root namespaces even if there is no server type there.
- Use a namespace for
Criteriaas TypeScript 6/7 produces an incorrect dts file. - Add
noUncheckedSideEffectImports: falseto Serene tsconfig.json. - Switch to FullCalendar 7.0.2 (unified package), which has breaking changes; the Calendar sample is updated accordingly (StartSharp).
- Replace the X.PagedList NuGet package reference, which is not updated for some time, with a minimal internal version of X.PagedList (StartSharp).
- Implement better indentation for markup generated from cshtml file for sidebar (StartSharp).
- Bump dompurify to 3.14.13, jsdom to 30.0.1, vite to 8.2.1, tiptap to 3.30.0, esbuild to 0.28.2.
- Bump preact to 10.29.8, vite to 8.2.1, esbuild to 0.28.2, @preact/signals to 2.11.0, @types/google.maps to 3.65.5, highlight.js to 11.11.2, datatables to 3.0.1 (StartSharp).
- Bump SQLitePCLRaw.bundle_e_sqlite3 to 3.0.5, NUglify to 1.22.3, Scriban to 7.2.6, ClosedXML to 0.105.1, Microsoft.Data.Sqlite to 10.0.11, MySqlConnector to 2.6.2, System libs to 10.0.11, PuppeteerSharp to 25.5.0, and Microsoft.Playwright.Xunit.v3 to 1.62.0.
- Remove Microsoft.TypeScript.MSBuild from Feature.Build.props and sample Directory.Build.props.
- Recommended
@serenity-is/tsbuildversion is now10.3.7which usesesbuild 0.28.2.
- Reject protocol-relative URLs in
isSafeReturnUrl, so inputs like//evil.exampleare no longer considered safe, fixing an open redirect issue (CWE-601, GHSA-9qr4-c5fv-3vwm). - Ignore
CancellationTokenparameters when generating service typings, so service endpoint methods taking aCancellationTokenno longer fail silently and now get a client proxy (#7421). - Also listen for the
inputevent in QuickSearchInput, as Playwright only triggers the input event.
- Modified the
PrefixedContextconstructor to optionally accept an object with{ idPrefix: string, domNode: HTMLElement }, e.g. aWidget, and a second optionalcontext: HTMLElementargument. This allowsFormobjects to still work with detached widgets like dialogs. GeneratedForm.tsconstructors now use this constructor. When creating form objects, instead ofnew CategoryForm(this.idPrefix), usenew CategoryForm(this)to use this ability. Also removed the legacyw0,w1etc. aliases in generated forms. - Support stable decimal ordering for dynamic navigation items, e.g. for a CMS. Changed navigation order storage to decimal. Heals duplicate static orders deterministically, preserving
int.MaxValueas the unset-order sentinel, resolving generated unset orders near their siblings, and using depth-based spacing for healed orders. - Use
IMPORTFROMCORELIBinstead ofQIMPORT,SERENITYIMPORTetc. in scriban templates when importing types from@serenity-is/corelib. The old names still work for compatibility, but custom scriban templates should be updated to use the new unified function.
- Fix issue where C# code generated by
sergen mvctduring build is not included in Compile items in Serene, causing the build to fail first time when a new editor type etc. is defined.
- Make EntityDialog methods like
save,loadById,delete, etc. return a promise. This might be a breaking change if you have any code that overrides these methods and does not return a promise. - Apply EntityDialog promise return changes to EntityGridDialog (StartSharp)
- Bring back custom component overload for the
jsxfunction. - Switching to TypeScript 7.
dts-bundle-generatorstill needs to use TypeScript 6 as TS7 does not have an API yet. - Allow
editSettingsfunction inAddExceptionLoggerextension (StartSharp) - Add tests for
autonumeric,ui/dialogs,ui/filtering,ui/helpers,ui/widgets,validator,layout,router,strings-compat,remoteview,fluent,fluent-events,services,pubsub, andinit-global-mappings. - Increase test coverage across corelib and UI modules.
- Generate/update dts files for new test additions.
- Fix domwise SVG presentation attributes never removed on re-assignment (
removeAttributeNScalled with swapped arguments). - Fix
<select>value broken with signals —assignPropnow handlesHTMLSelectElement(single & multi-select). - Fix Show component memory leak —
lifecycleNodeno longer set to non-EventTarget values (e.g. string children). - Fix
derivedSignalfallback crash whensubscribedoesn't fire synchronously. - Fix
unsignalizePrevClassto recursively handle nested arrays. - Fix spellcheck cast from
HTMLInputElementtoHTMLElement. - Fix
getContentparameter type in Show. - Fix some potential issues in
ui/helpersandui/widgets. - Fix some minor bugs in validator.
- applyFormatterResultToCellNode sets innerHTML instead of innerText when enableHtmlRendering is false, causing wrong content to be rendered on cell updates
- Add RegisterScoped, RegisterSingleton, RegisterTransient attributes that allow an implementation type to be auto registered for any interface (excluding ones deriving from IRequestHandler) in Startup.cs ConfigureServices method by calling services.AddAutoRegisteredServices(); which should be the last line in that method.
- Use
node --run scriptnameinstead ofpnpm scriptnameornpm run scriptname - Allow passing dialogType option of combo/lookup editors as a type / promise instead of string
- Remove all
javascript:urls for links as they are incompatible with strict CSP, or replace them with a role="button". - Expose uploader object via new createUploadInput helper
- Add Blog sample under
Application Samples(StartSharp) - Add missing
commitEditsfunction to EntityGridDialog. Add test to catch missing EntityDialog prototype functions in EntityGridDialog.
- Clear cssColRulesL/R and cssVarRules to avoid issue when switching back from useCssVars in SleekGrid
- Remove
\nand\tfrom<span class="counter"/>texts and make sure display text shown properly even if they have such characters. - Ensure
HeaderFiltersPlugin.getFilterValuedoes not fail when value is null / undefined.
- Validate the language ID passed is a valid ISO language ID (e.g. en-GB) before saving translations.
- Rename useGridEditorSave to useGridEditorServices to better match intent (e.g. save and delete)
- Define hasDeletePermission, hasInsertPermission etc. also in EntityGrid
- Export isAddRowSymbol from corelib
- Auto register function for GridEditController (StartSharp)
- Add hasInsertPermission, hasUpdatePermission and canEditItem options to GridEditController
- Use hasDeletePermission method from the grid if available, or use hasDeletePermission option of GridEditController if specified (StartSharp)
- Add isReadOnly option to GridEditController, if not specified check grid's get_readOnly method / readOnly property (StartSharp)
- Set grid's options.editorLock to a new one if default options editorLock is set to null. This allows setting gridDefaults.editorLock to null to automatically create a new one when required. Using GlobalEditorLock may cause some issues between editable grids in different unrelated dialogs.
- Add tabbable option (default true) to columns which controls navigation via tab key. If a column is focusable: false, this property has no effect.
- New TabbableAttribute that sets tabbable option for columns.
- Rename SelectableAttribute to ShowSelectionAttribute to better identify intent and usage in SleekGrid, as it only controls if "selected" css class should be applied to cells, not selectability of a cell.
- Null reference issue when grid inline editor's inplace add button is clicked and another inplace editor grid is opened
- Add Focusable(false), Selectable(false) to RowEditActionsColumnAttribute
- Derive IPropertySource from IPropertyInfo
- Add origin argument to IPropertyInfo.GetAttribute and IPropertyInfo.GetAttributes method to selectively exclude inherited, intrinsic, based on field attributes.
- Make ReflectedType available through IPropertySource so that IPropertySource.Property does not need to be used and might be removed in the future to allow dynamic/mock props.
- Add SelectableAttribute and FocusableAttribute and use them in setting grid columns corresponding props.
- Add GetAttributesWithIntrinsic helper and use it instead of GetAttributes to also check intrinsic attributes added via IIntrinsicPropertyAttributeProvider in sergen and Pro.Coder for code generation.
- Ensure BasedOnRowPropertyNameAnalyzer takes intrinsic attributes provided via an IIntrinsicPropertyAttributeProvider into account
- Deprecated GetAttribute method had
inherit: falseas default, instead of GetCustomAttribute which hasinherit: trueby default, resulting in [DefaultHandler] issues when a base class with [DefaultHandler] attribute is used.
- Improve error handling for unhandledRejection (e.g. async) errors
- Add IIntrinsicPropertyAttributeProvider which allows creating combination attributes for usage in forms / columns.
- RowEditActionsColumnAttribute for grid editors which is a combination attribute implementing IIntrinsicPropertyAttributeProvider.
- ReflectionExtensions.GetAttribute is now obsolete and will be removed, use GetCustomAttribute.
- Better async error handling for inline editing, also validate invisible columns and show a notification if a required column is invisible (StartSharp)
- Add ability to change autoEdit option in GridEditController (StartSharp)
- Commit current row changes via Ctrl+Enter key in GridEditController (StartSharp)
- Changed default for GridEditControllerOptions.actionsColumn (previously actionColumn) to
RowEditActions(StartSharp). - Add a GridEditController.createActionsColumn function to manually create an
RowEditActionscolumn (StartSharp).
- Pass the full entity, e.g. merged with existing item to the validateEntity method, instead of only the request.Entity fields which might only include changed fields in inline editing mode.
- Update modified css classes after cancelling row adding (StartSharp)
- GridEditController.deleteHandler receives a wrong defaultHandler argument
- GridEditController now support inline row adding. The add row can be placed at the top, bottom and optinally be a fixed/sticky row.
- Switched to TypeScript 6, which has several breaking changes. Most notably, you should set
"strict": falsein your tsconfig.json asstrictistrueby default now. - Support
${configDir}variable intsconfig.jsonfiles which is useful forextendsand config file relative paths. - Add
RemoteView.onRecalcRowsevent to intercept recalc method before getting the row diffs, e.g. to inject some special rows like special / fixed location ones which are ignored in filtering / grouping calculations. - Make it possible to get/set RemoteView.itemMetadataCallback.
- Add a DeleteRowActionFormatter (Serenity.Extensions) and use it in OrderDetailsEditor to add a delete row action column, add getCreateServiceMethod, getDeleteServiceMethod, getUpdateServiceMethod methods to the GridEditorBase.
- Add an async commitEdits method to property grid so that any pending edits can be asynchrously committed before the dialog itself is saved, useful for inline grid editors etc.
- Bootstrap tooltip workaround for twbs/bootstrap#37474
- Switched to xUnit v3 for unit testing
- Switched to Playwright from Selenium for browser functional tests
- Added Recaptcha urls to CSP directives (StartSharp)
- Use initial value passed to the addIncludeDeletedToggle callback
- Use logic for always visible / hidden columns also for data grid persistence
- Add sample for adding maximize button to modal in ChartInDialog sample
- Also add dragging ability to the modal in ChartInDialog sample. Split modal utility code.
- Add onSetViewParams event to DataGrid and attach to it instead of onSubmitting event in HeaderFiltersMixin, as if onViewSubmit is manually called instead of prepareSubmit, ExcelExportHelper won't be able to set its filters as onSubmitting won't be triggered.
- Add Criteria and Distinct support to DataExplorer
- Fix Columns with FilterOnly attribute or the ones that does not have the ReadPermission should not be shown in the column picker
- Revert unintentional UserPage and AccountPage changes in StartSharp which was made to reproduce a bug
- Skip types from non-local modules in node_modules in addition to types from declaration files in client types generator to avoid generating duplicate editor, formatter attributes etc. for types in project package references.
- New Serenity Developer Tools extension for Chrome
- New
DENYspecial permission that denies access to everyone including super admins. - Define UploadPathHelper.TemporaryFilePrefix and UploadPathHelper.IsTemporaryFile and use them instead of hardcoding temporary/
- Add thumbnail metadata and helpers to find a primary file from the thumbnail file
- Add FileReadAccessAttribute and FileReadAccessSettings that will be used by SecureUploadFileResponder (currently experimental in pro.extensions)
- New SecureUploadFileResponder (in pro.extensions) that checks for related entity access, and optionally permissions while returning files from FilePage/Read.
- Update jQuery to 4.0.0 (served via Serenity.Assets for compat). Note that it has some breaking changes like removing $.isArray, so stay at 3.7.0 via npm if you have problems
- Remove unused global type helpers (Action, Predicate etc.) that sometimes clash with other globals. Include ESNext.Disposable as signals-core requires it
- Try more package names like
@company/package,company.packagefor an assembly name likeCompany.Packagein ServerTypingsGenerator. Also try to parse assembly to package name mappings from package.json.
- Issue with generated MVC file when C# keywords like
decimalare used as.cshtmlfile names. - Add disposing listener to the target element during addValidationRule to resolve issue when the editor with custom validation rule itself is disposed in inline grid editors and validation callbacks are executed. Also add null coalescing to DateEditor, DateTimeEditor get_value methods for this.domNode? to avoid issues for similar cases.
- Empty header filter dropdown contents before appending the search results
- Fix issue with DateOnly field due to the format string extra quote
- Revert Sergen to generate DateTime fields as before for SQL date columns as DateOnlyField is not yet stable
- Add a PropertyProcessor:DefaultSummaryType setting that can be set to None, Disabled, etc., to override the default Sum aggregate type for numeric columns. For example:
services.Configure<PropertyProcessorOptions>(options => options.DefaultSummaryType = SummaryType.None)sets the default to None but still allows users to choose via the header menu, etc.
- The summary footer value is not shown the first time when no columns have summaries and one is set via the column header menu (e.g., when the footer row is toggled).
- Change the min/max values for date/time editor attributes to strings, as DateTime cannot be used as an attribute property value.
- Handle the issue when a
Sortable(false)column is included in the server-side generated sorted column list.
- Introduce a new GridUtils.addQuickSearch method with named arguments, replacing the deprecated addQuickSearchInput and addQuickSearchInputCustom methods.
- Handle Shift+Wheel for horizontal scrolling in SleekGrid.
- Fix formatting issues with CheckTreeEditor/CheckLookupEditor and the quick search indicator.
- Override Equals and GetHashCode for PageAuthorizeAttribute, as the default implementation of Attribute.Equals throws a stack overflow when the permission keys are the same for the action and controller, causing Swagger to fail when enumerating attributes for the action.
- Add AntiforgeryFilter options: SkipValidationHeaderName (default "X-CSRF-SKIP") and SkipValidationHeaderValue (default "true"). When present in the header, these will skip CSRF validation when using AutoValidateAntiforgeryIgnoreBearerFilter. This makes it easier to work with clients that use cookie authentication (not bearer tokens) by adding the header.
- The Serenity.Pro.Extensions global init script passes an invalid case
proExtensionsinstead ofproextensionsto initGlobalMappings.
- Generate an ESM-style script from the tsbuild externalGlobals plugin for Serenity modules instead of CommonJS, by parsing .js files via es-module-lexer. This should result in more optimized output.
- Set the target to ES2022 in tsconfig.json files.
- Shorten Dutch header menu texts, use "auto" for the label column in header menu split actions, and set overflow to hidden with ellipsis for dropdown items under split actions.
- Use toUTCString instead of the deprecated toGMTString or toISOString (not supported for cookies) when setting cookie expiration time for Language/ThemeSelection.
- All scripts now target ES2022, which is supported by all current major browsers.
- Add the AddSerenityAssetsImportMapEntries extension for adding jspdf and tiptap import map entries from ~/Serenity.Assets in _ImportMap.cshtml, instead of manually specifying individual entries.
- Use .bundle.js and .bundle.css suffixes instead of -bundle.js and -bundle.css for consistency.
- Fix the temporary column scroll synchronization issue when hiding or showing a column via the column picker.
- Fix the PermissionCheckEditor onClick event name.
- Introduce new AddImportMapEntry and RenderImportMap extensions in HtmlScriptExtensions, which can be used in layout pages to prepare import maps and optionally add external URLs to CSP (enabled by default).
- Export jspdf and jspdf-autotable from ~/Serenity.Assets/jspdf/jspdf-autotable.bundle.js and use them from PdfExportHelper instead of CDN, which may be problematic for strict CSP and disconnected scenarios. They can also be overridden via import map entries for
jspdfandjspdf-autotable. - Also build ~/Serenity.Assets/tiptap/tiptap.bundle.js to make it easier to update tiptap packages for apps. This can be overridden or mapped via an import map entry for
@serenity-is/tiptap; see_ImportMap.cshtmlin the latest templates. Local npm installations for tiptap modules in templates are removed.
- The tsbuild clean plugin was not functional by default; update
@serenity-is/tsbuildin package.json to 10.0.7 to resolve the issue.
- Fix the issue where the report .cshtml file could not be located due to IActionContextAccessor being made obsolete in .NET 10.
- Add https://cdnjs.cloudflare.com/ajax/libs/ to the CSP script-src directive for jspdf dynamic loading.
- Allow the TransformIgnore attribute on methods.
- Improve handling for complex or unresolvable types during server types generation by using "unknown" as the type and printing the problematic type as an inline comment. Note that this may now include members of non-standard types like interfaces and abstract types, which were previously skipped.
- Missing package.json in NuGet packages for assets, corelib, etc.
- Missing targets file in Serenity.Net.Web.
- Make it possible to optionally provide files under wwwroot via npm / nuget package to node_modules/.dotnet. Also include feature project's package.json in the NuGet package and use it while restoring packages. Adapt TinyJSON code to for a stable JSON parser / writer in RoslynCodeTaskFactory without having to reference System.Text.Json or Newtonsoft.Json within RestoreNodeTypesTask.
- Added a patched local copy of glightbox to Serenity.Assets as it has issues with CSP
- Migrated from .sln to .slnx format which is simpler and readable.
- Export domwise from corelib so that it's code is not duplicated by every feature project requiring it
- importAsGlobalsMapping now maps all (sleekgrid, corelib, extensions etc) to Serenity namespace by default.
- Define initGlobalMappings helper which setups global variables for Serenity libs like corelib, sleekgrid, extensions, pro.extensions in addition to optionally third party libs like bootstrap. This can be used to potentially remove appsettings.bundles.json and pass globals to feature packages that requires it.
- Add custom DateTimeOffset parsing to ObjectJsonConverter for Newtonsoft.Json compatibility (#7391)
- Move CheckUnassignedRead to IRow interface for consistency with FieldAssignedValue
- Rename Field.GetIsNull to Field.IsNullNoCheck similar to AsObjectNoCheck
- Rename IRow.FieldAssignedValue to OnFieldSet, IRow.CheckUnassignedRead to OnFieldGet to better emphasize they need to be called before getting / after setting a field value for checks / tracking to work. These methods are used internally so should not be a breaking change.
- Implement faster property get / set methods for partial row properties generated via
[GenerateFields]attribute. - Add ability to set include / exclude glob patterns for tsbuild cleanPlugin.
- Add compression option to writeIfChanged plugin and tsbuild options via compress property. Brotli is too slow (15x slower than gzip) even with quality: 4, so only gzip is recommended for now. This is not recommended to be used for now as static web assets SDK also does its own compression.
- Add a PreCompressedFileProvider that may serve .gz, .br compressed files if available. These are produced by static web assets SDK during build and publish.
- Added buildGlobalBundles option to tsbuild to automatically bundle files under Modules/Common/bundles/*-bundle(.css|.ts). StartSharp now uses this to generate its bundles instead of appsettings.bundles.json.
- Use l10n bundle and initGlobalMappings function in flatpickr-init
- Remove Pages/Dashboard css bundle as can directly import @serenity-is/pro.extensions/pages/dashboard.css from DashboardPage.tsx
- Merge pro-theme.js into Pro.Extensions/index.js. The one in appsettings.bundles.json should be removed.
- Converted JsonRequest attribute to async, disabled AllowSynchronousIO in Startup.cs. This was crashing in .NET 10 under Ubuntu.
- New AddServiceEndpointConventions extension for usage in Startup instead of adding services / conventions manually.
- Serenity.DomWise and Serenity.SleekGrid will be released along with other Serenity libs and use the same version with other libs
- Most of the static files inside Serenity.Assets package is generated from npm packages instead of libman.json.
- Sync pnpm install tasks via a mutex.
- AddCspDirective overloads for ControllerBase and HttpContext
- Fix remaining discovered CSP related issues in sample pages
- 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.
- AddCspDirective overloads for ControllerBase and HttpContext
- Fix remaining discovered CSP related issues in sample pages
- This will be the last version using .NET 8, only minor 9.2.x versions from
net8branch may be released to fix any critical issues. - 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
HtmlNoteContentEditorandHtmlReportContentEditorto useTiptapinstead ofCKEditor(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
useUpdatableComputedhelper indomwiseto 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.
- Fix potential issue with SlickFormatting.treeToggle when formatter returns a string, and enableHtmlRendering is false. Update the default comment in FormatterContext.enableHtmlRendering
- Null flags issue when restoring persisted settings
- Improve column picker dialog toggle all handling so that only one populate necessary when multiple columns are shown
- Stored the used persistence flags in persisted grid settings.
- Improve HTML content editor validation handling
- Add getFilteredItems method to IRemoteView interface, remove comments from RemoteView methods that already has comments in IRemoteView
- Bump glob to 12.0.0, vitest to 4.0.10, jsdom to 27.2.0
- @serenity-is/tsbuild 9.1.6 with updated glob dependency
- Fix gridradioselectionmixin using html string
- Enhance type system for attributes and interfaces. Add CustomAttribute base class for extensible attribute support and attribute typing. Introduce AttributeSpecifier union type for flexible attribute specification (classes, instances, factories). Update registerClass, registerEditor, registerFormatter to handle AttributeSpecifier. No need to call Attributes.factoryFunction() as it will be called by registration helper automatically (e.g.
[Attributes.someAttr]is enough). Similarly, newSomeAttributeClass()is not necessary when passing attributes.
- Potential this issue in setTimeout for asyncPostProcess
- Fix wrong isImmediatePropagationStopped check in onDragInit causing inputs to not get focus in the grid
- New Column Picker Dialog which only has one set of columns (e.g. not split by visible / hidden) and has checkboxes to toggle visibility. It also applies changes as soon as a checkbox is clicked or columns dragged. The new one can also work with raw SleekGrid, or any other component with columns as long as necessary callbacks are provided.
- Use the IRemoteView interface in RemoteView events
- Provide more info from sleekgrid.getLayoutInfo method about column pinning / frozen rows ability
- Fix actions dropdown visibility issue due to slick-cell having a z-index value in base.css
- Fix some actions in header menu failing due to losing this context when calling preventDefault
- Fix an issue with System.Data.Common reference in sergen g
- Redesigned SleekGrid event system as the previous one caused some issues when it is used in a site that has jQuery loaded. Only a subset of Args properties (grid, column, row, cell etc) are passed through the event argument, while the rest can be accessed via second args parameter, or e.args.
- Changed view namespace for .cshtml files to
MyProject.Views(for /Modules) andMyProject.Views.Shared(for /Views) by default to avoid potential namespace problems
- Converted formatters in Serene Translation page to JSX syntax as HTML strings no longer supported by default
- Add coalesce to quickFilterParams as Object.assign fails when it is null
- Add submitOnEnter and closeOnEscape options to PromptDialog (defaults to true, can be modified by setting PromptDialog.defaultOptions).
- Add PromptDialog.getEditor method to access the editor.
- Pass known options from editor options to the autonumeric instance from integer/decimal editors.
- Improve login page 2FA code entering UI experience (StartSharp).
- Add
[hidden] *to validation ignore default list, just like.hidden *.
@serenity-is/domwiseis 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/domwisealso exports signal functions likesignal,computed,effectetc. from@preact/signals-coreand supports signals as attribute values and element children, and reactively updates the attributes and dom nodes when signal values change. Please removejsx-domfrom yourpackage.json, and set thejsxImportSourceto@serenity-is/domwise. There are a few differences betweenjsx-domanddomwise. The HTML element attributes are lowercased to match the actual HTML attribute casing, e.g.,readonlyinstead ofreadOnly,forinstead ofhtmlFor. We aliased some liketabIndex,htmlFor,maxLengthetc. for easier transition. This should make it easier to copy/paste actual HTML code to our.tsxfiles, 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.EnhancedLayoutis enabled by default for all grids in StartSharp, though pinning / frozen rows are opt-in via column menu / options. If you were usingFrozenLayoutin some of your grids (by overridinggetSlickOptions), 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,DraggableGroupingMixinandHeaderFiltersMixinnow 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 viaModules/Common/script-init/autoregister-init.tsfile 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
showPanelWhenNoGroupsthat, if set to false, hides the grouping bar (one with textDrag a column here...) when there are no grouped columns. - CustomSummaryMixin offers an option named
showFooterWhenNoSummariesthat, 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.ScriptSkipstill exists but is deprecated. The old name felt a bit like 'skip this on the client/script side'. - Renamed
[Ignore]attribute toIgnoreUIFieldto better match the intent, e.g., ignoring the generation of column / form fields for that property.Ignoreattribute still exists but is deprecated. The old name was not clear enough. - Renamed
IgnoreNameAttributetoSkipNameCheckAttributeto better match the intent.IgnoreNameattribute 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) toSleekGridto avoid mix-ups withDataGrid,EntityGridand other grid types. - New
Attributesnamespace which works similarly to the@Decoratorsnamespace for [Symbol.typeInfo] style type registration, e.g., [Attributes.panel()] instead of [new PanelAttribute()] - The
FilterableAttributewhich used to control advanced filtering on grids via a bottom filter bar and an advanced filter dialog is renamed toAdvancedFilteringAttributewhich you may use viaAttributes.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 inDataGridsubclasses that is used to create the initial column set for a grid, but because its name matched theSleekGrid'sgetColumns()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 ofdataGrid.sleekGrid.getColumns(). Please overrideprotected createColumns()method instead which better matches the intent. To access currently visible columns for a data/entity grid, you may use.columnsproperty, or.sleekGrid.getColumns(). To access all the columns (including invisible ones, not necessarily matching the visible order) use.allColumnsproperty or.sleekGrid.getAllColumns(). - For compatibility with jQuery, we previously chose to set
style.displaytononewhen an element is hidden viaFluent.togglemethods. We now decided to use thehiddenattribute which applies to all element types, and actually hides the element even if thestyle.displayproperty is overridden by a Bootstrap class liked-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 Gridlayout 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/sleekgridfolder 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/corelibnow also has asanitizeHtmlfunction 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]**) asgridDefaults.enableHtmlRenderingis 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 (viadomwiseetc). 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:AsNamespaceoption to sergen.json which causes a.MVCnamespace suffix to be generated instead of anMVCclass. When enabled, theESMhelper class will also be generated under this namespace, e.g.,RootNamespace.MVC. This should reduce confusion when a namespace likeSerenity.Extensionsis added to global usings as it also has its ownMVChelper. The default is false for now, as it would be a problem forESM.references, as they would need to be written asMVC.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 newdefaults@9.0.0insergen.jsoncan be used instead ofdefaults@6.6.0to enable this flag by default (new projects will also usedefaults@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 mixin to the plugin. Added more options to checkbox/boolean formatter and special handling for 'header-filter' purpose
- Added tests for broken source links to Serenity demo pages
- The source links for sample pages in Demo now point to the commit used at the time of publishing instead of the master branch.
- New SleekGrid formatterContext helper that should be used instead of directly creating a formatter context as this helper will set sanitizer, escape and other arguments correctly based on global / grid options.
- Deprecated groupTotalsFormatter and use groupTotalsFormat that accepts a FormatterContext instead, similar to column.format
- Added a sample to show country flags in Customer / Supplier pages.
- New
bindThis(this).someFunctionhelper method in@serenity-is/sleekdomto auto-bind class functions instead ofthis.someFunction.bind(this)which creates a new function every time, and makes unsubscribing from events difficult. **[Breaking Change]**Instead of a.hiddenclass we now use HTML standard "hidden" attribute/property.- Added a debounceTimes option to LayoutTimer to avoid momentarily changing dimensions to trigger layout events.
- Purpose parameter passed to formatters to identify for what purpose the formatter is called like 'header-filter', 'group-total', etc.
- Removed legacy Exception, ArgumentException classes.
- Converted RemoteView into a proper class with private and public members
- Removed unused inlineFilters option from RemoteView.
- Removed legacy fastSort function from RemoteView.
- Converted aggregators to proper classes, removed pre-compiled aggregators
- Moved JS reserved keyword list to CodeWriter, commented JS reserved words while generating texts.ts.
- Added asKey() and asTry() methods to generated text namespaces which will be handled by proxyTexts.
- Converted type registries to proper classes instead of a helper function
- Added isSafeReturnUrl function, and used it in getReturnUrl instead of the simple check
- Simplified Unicode email validation regex
- Used AuthorizeRetrieve attribute in generated endpoint Retrieve method
- New AggregatorTypeRegistry that registers Aggregator types that contain summaryType, aggregateType, and displayName static properties
- Merged ReflectionUtils and ReflectionOptionsSetter
- Updated handler templates to use [GenerateFields] and use the
.RequestHandlersnamespace suffix if EnableGenerateFields is true. Got rid of MySaveRequest etc. aliases in handler templates. - Parse global usings from project and allow passing them via -globalusings to Sergen
- Updated many NPM/NuGet packages, including System/ASP.NET Core ones to 9.0.10, esbuild to 0.27.0, Microsoft.Data.SqlClient to 6.1.2, Microsoft.TypeScript.MSBuild to 5.9.3.
- When any cell in the last row of a full size grid with a
Select2dropdown is clicked, asSelect2tries to position its dropdown momentarily, a page scrollbar is shown. This triggered a layout event in the grid, causing it to hide the editor due to a full re-render. Another similar issue was present in theProductpage with legacy editor inputs and the Android touch keyboard. These issues are now fixed, andSleekGridshould perform better with mobile devices. - Fixed some potential compatibility issues with .NET 10 like Enumerable.Reverse/Array.Reverse(span) overloads.
- Fixed SMS two factor method raising an exception (StartSharp) when user does not have a mobile number
- Dump SQL server parameter types properly if parameter is a SqlClient.SqlParameter
-
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: trueintsconfig.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
thisexpression 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 theregisterTypestatic method inWidgetcallsclassTypeInfoandregisterTypeinternally.This style is also useful for formatter registration, as formatters typically do not have a base type and cannot simply call
this.registerTypelike 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
FormatterBaseclass: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.tsfile, 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
EditLinkfunction that can be used instead ofSlickHelpers.itemLinkwith JSX elements. TheDataGridalso has anEditLinkarrow 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
ServerTypingsGeneratorare now ordered and organized. -
You can now pass
formatterTypeby reference inPropertyItem. -
Added a
valueargument to theValidator.optionalmethod, allowing validation methods to be called without an element—just a value—when desired. -
Adjusted the
Validator'sonfocusoutmethod: 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
getPropertyItemoption to optionally override the column item. - The
bulkSaveHandleroption now works. - The
saveHandlercallback receives anargsargument with adefaultHandlerproperty, allowing you to call the default save handler when needed.
- New
-
Splitted WizardDialog's renderContents method into renderButtons, renderCancelButton, renderBackButton, renderNextButton etc. to make it easier to modify/inject content (StartSharp)
- Extract commit ID from assembly / nuget package generated by SourceLink and use that instead of master branch to link to source files for demo
- Containg folder name of several projects are changed (for example Serenity\src\web\Serenity.Net.Web.csproj instead of Serenity\src\Serenity.Net.Web\Serenity.Net.Web.csproj). This may only affect you if you are using Serenity via submodules.
- Updated OpenIddict to 7.0.0
- Use Fluent.addClass as opt.cssClass passed to quick filter element might contain spaces
-
Added Html.CspNonce() helper function and made it possible to optionally enable CSP by uncommenting and adjusting Content-Security-Policy meta element in _LayoutHead.cshtml
-
Also register addon option values as local text keys if they match the candidate regex
-
Run TSBuild target before ResolveProjectStaticWebAssets abd clean content items to resolve issues with static web assets issues in NET9 SDK.
-
Add npmCopy helper function to tsbuild that copies files under node_modules/ to wwwroot/npm/ folder. Used it to copy flatpickr, moment, chartjs and other scripts used in DashboardIndex to wwwroot/npm for use in appsetting.bundles.json. The entries in appsettings.bundles.json that start with ~/npm/ will be automatically copied from node_modules/ to wwwroot/npm/ by default.
-
Add Modules/**/*.mts to default entry points
-
Add ability to localize input add-ons text/hint if the value is a local text key
-
Converted UI samples to use .tsx instead of .cshtml files
-
Exception Log page is now using
Administration:ExceptionLogpermission instead ofAdministration:Securitypermission. -
Updated .NET libraries including:
- ASP.NET Core framework packages to 9.0.8
- ClosedXML to 0.105.0
- FirebirdSql.Data.FirebirdClient to 10.3.3
- FluentMigrator to 7.1.0
- Microsoft.Data.SqlClient to 6.1.1
- Microsoft.TypeScript.MSBuild to 5.9.2
- NUglify to 1.21.17
- Npgsql to 9.0.3
- SixLabors.ImageSharp to 2.1.11
-
Updated NPM packages including:
- chart.js to 4.5.0
- dompurify to 3.2.6
- esbuild to 0.25.9
- glob to 11.0.3
- preact to 10.27.1
- typescript to 5.9.2
- vitest to 3.2.4
-
**[Breaking Change]**Split IInsertLogRow into IInsertDateRow and IInsertUserRow subinterfaces. Split IUpdateLogRow similarly. Replace IInsertLogRow.InsertUserIdField with IInsertUserIdRow.InsertUserIdField, IUpdateLogRow.UpdateUserIdField with IUpdateUserIdRow.UpdateUserIdField, IInsertLogRow.InsertDateField with IInsertDateRow.InsertDateField, and IUpdateLogRow.UpdateDateField with IUpdateDateRow.UpdateDateField if you implemented these interfaces in your rows -
[Breaking Change]Removed following scripts from Serenity.Assets. If you still need these legacy scripts (e.g. in appsettings.bundles.json) you may install them via npm / libman.json or use them via CDN:- jquery.colorbox (prefer glightbox from npm, we use it in StartSharp now)
- jquery.cookie
- jquery.event.drag
- jquery.maskedinput
- jquery-ui
- jquery-ui-i18n
- jspdf (if not available, PDFExportHelper will try to load it from CDNJS by default)
- jspdf.autotable (if not available, PDFExportHelper will try to load it from CDNJS by default)
-
[Breaking Change]Removing ckeditor from Serenity.Assets. HtmlContentEditor will load it (v4.22.1) from CDNJS by default. Please remove lineHtmlContentEditor.CKEditorBasePath = "~/Serenity.Assets/Scripts/ckeditor/"from ScriptInit.ts.
- Resolve issue with multiple file drag drop on uploader due to event.dataTransfer.items array getting lost during async call
- Disable each individual radio button for RadioButtonEditor when switching read only, closes #7372
- Fix extending entry points with "+" does not work in tsbuild
- A new Interface source generator that may automatically generate relevant service handler interfaces for handler types with
[GenerateInterface]attribute. - Update esbuild to 0.25.5. Warning! Please set
"experimentalDecorators": truein your tsconfig.json as esbuild has an unresolved bug with decorators and initializers (evanw/esbuild#4092). You may have script errors otherwise! - Introduced experimental DateOnlyField type. This required changing target framework of Serenity.Net.Services to net8 (was netstandard2.1).
- Add Oracle-specific SQL type mappings to SqlTypeToFieldTypeMap (#7363)
- Add support for partial properties for row fields source generator (requires NET9+)
- Also invalidate UserRole / UserPermission cache group when saving user as LinkingSetRelation might be updating roles
- Update SixLabors.ImageSharp to 2.1.10
- Fix quoting of UPPER field expression for case sensitive like dialects
- Add ability to intercept some SQL operations done through SqlHelper and EntityConnectionExtensions by implementing ISqlOperationInterceptor and/or IRowOperationInterceptor in the mock connection class.
- Switched to vitest from jest for javascript tests
- Try to avoid issue when StringField reads value via Newtonsoft.Json and a DateTime token is received
- Updated nuget/npm packages
- New writeIfChanged option in tsbuild to accelerate builds in VS
- Also allow DefaultHandler(false) to skip a handler when multiple handlers for a type is found
- AuthorizeRetrieveAttribute that may be used for endpoint Retrieve methods
- Go back to StackExchange.Exceptional from our temporary fork (Serenity.Exceptional.AspNetCore) as in 3.0.1 version they also switched to Microsoft.Data.SqlClient
- Fix PasswordStrengthValidator not correctly validating MembershipSettings.RequireDigit rule (#7306)
All Serenity versions published in the year 2024 (versions 8.2.1 through 8.8.3) can be found in changelog-2024.md.
All Serenity versions published in the year 2023 (versions 6.4.3 through 8.1.5) can be found in changelog-2023.md.
All Serenity versions published in the year 2022 (versions 5.1.2 through 6.4.2) can be found in changelog-2022.md.
All Serenity versions published in the year 2021 (versions 5.0.20 through 5.1.1) can be found in changelog-2021.md.
All Serenity versions published in the year 2020 (versions 3.10.0 through 3.14.5) can be found in changelog-2020.md.
All Serenity versions published in the year 2019 (versions 3.8.4 through 3.9.14) can be found in changelog-2019.md.
All Serenity versions published in the year 2018 (versions 3.3.15 through 3.8.3) can be found in changelog-2018.md.
All Serenity versions published in the year 2017 (versions 2.8.0 through 3.3.14) can be found in changelog-2017.md.
All Serenity versions published in the year 2016 (versions 1.8.19 through 2.7.2) can be found in changelog-2016.md.
All Serenity versions published in the year 2015 (versions 1.4.7 through 1.8.18) can be found in changelog-2015.md.
All Serenity versions published in the year 2014 (versions 1.3.0 through 1.4.6) can be found in changelog-2014.md.