Compare commits

...
Author SHA1 Message Date
Ronald Barendse d8ce6901de Persist document URLs under distributed-cache-only notification publishers 2026-06-26 14:43:22 +02:00
b836b44343 Table dates and User dates (#22169)
User-collection-table didn´t format and if you have da backoffice the time is still Am/pm

Co-authored-by: Lucas Bach Bisgaard <lucas.bisgaard@kraftvaerk.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-06-26 09:24:35 +02:00
6 changed files with 44 additions and 9 deletions
@@ -1,4 +1,4 @@
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services.Changes;
@@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.Services;
/// is delivered to other servers, ensuring URL data is in the database before any server processes the instruction.
/// </summary>
public class DocumentUrlServiceContentTreeChangeNotificationHandler
: INotificationAsyncHandler<ContentTreeChangeNotification>
: IDistributedCacheAsyncNotificationHandler<ContentTreeChangeNotification>
{
private readonly IDocumentUrlService _documentUrlService;
private readonly IDocumentUrlAliasService _documentUrlAliasService;
@@ -9,7 +9,7 @@ export class UmbDateTableColumnViewElement extends UmbLitElement {
override render() {
if (!this.value) return nothing;
const date = new Date(this.value);
return html`${date.toLocaleString()}`;
return html`${date.toLocaleString(this.localize.lang())}`;
}
}
@@ -49,7 +49,7 @@ export class UmbDocumentTableColumnPropertyValueElement extends UmbLitElement im
case 'contentTypeAlias':
return { value: item.documentType.alias };
case 'createDate':
return { value: this._createDate?.toLocaleString() };
return { value: this._createDate?.toLocaleString(this.localize.lang()) };
case 'creator':
case 'owner':
return { value: item.creator };
@@ -58,7 +58,7 @@ export class UmbDocumentTableColumnPropertyValueElement extends UmbLitElement im
case 'sortOrder':
return { value: item.sortOrder };
case 'updateDate':
return { value: this._updateDate?.toLocaleString() };
return { value: this._updateDate?.toLocaleString(this.localize.lang()) };
case 'updater':
return { value: item.updater };
default: {
@@ -128,7 +128,7 @@ export class UmbLogViewerMessageElement extends UmbLitElement {
return html`
<details @open=${this.#setOpen}>
<summary>
<div id="timestamp">${this.date?.toLocaleString()}</div>
<div id="timestamp">${this.date?.toLocaleString(this.localize.lang())}</div>
<div id="level">
<umb-log-viewer-level-tag .level=${this.level ? this.level : 'Information'}></umb-log-viewer-level-tag>
</div>
@@ -139,7 +139,7 @@ export class UmbLogViewerMessageElement extends UmbLitElement {
<ul id="properties-list">
<li class="property">
<div class="property-name"><umb-localize key="logViewer_timestamp">Timestamp</umb-localize></div>
<div class="property-value">${this.date?.toLocaleString()}</div>
<div class="property-value">${this.date?.toLocaleString(this.localize.lang())}</div>
</li>
<li class="property">
<div class="property-name">@MessageTemplate</div>
@@ -161,7 +161,7 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
case 'contentTypeAlias':
return item.contentTypeAlias;
case 'createDate':
return item.createDate.toLocaleString();
return item.createDate.toLocaleString(this.localize.lang());
case 'name':
return item.name;
case 'creator':
@@ -170,7 +170,7 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
case 'sortOrder':
return item.sortOrder;
case 'updateDate':
return item.updateDate.toLocaleString();
return item.updateDate.toLocaleString(this.localize.lang());
case 'updater':
return item.updater;
default:
@@ -1,6 +1,7 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Persistence.Repositories;
@@ -38,6 +39,8 @@ internal sealed class DocumentUrlServiceContentTreeChangeTests : UmbracoIntegrat
private IContentService ContentService => GetRequiredService<IContentService>();
private IEventAggregator EventAggregator => GetRequiredService<IEventAggregator>();
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
private ILanguageService LanguageService => GetRequiredService<ILanguageService>();
@@ -139,6 +142,38 @@ internal sealed class DocumentUrlServiceContentTreeChangeTests : UmbracoIntegrat
}
}
/// <summary>
/// When operations run under a scoped notification publisher restricted to
/// <see cref="IDistributedCacheNotificationHandler"/>, the handler must still persist URL segments and
/// aliases to the database; otherwise the data only reaches the in-memory cache and routing is lost on restart.
/// </summary>
[Test]
public void Publish_UnderDistributedCacheOnlyPublisher_StillWritesUrlSegmentsAndAliasesToDatabase()
{
var page = ContentBuilder.CreateSimpleContent(ContentType, "Distributed Cache Page", RootPage.Id);
page.SetValue(Constants.Conventions.Content.UrlAlias, "distributed-cache-alias");
var publisher = new ScopedNotificationPublisher<IDistributedCacheNotificationHandler>(EventAggregator);
using (ICoreScope scope = CoreScopeProvider.CreateCoreScope(scopedNotificationPublisher: publisher))
{
ContentService.Save(page, -1);
ContentService.Publish(page, []);
scope.Complete();
}
Assert.Multiple(() =>
{
Assert.That(
GetDbSegments(page.Key),
Is.Not.Empty,
"URL segments must be persisted to the database even when publishing under a distributed-cache-only notification publisher.");
Assert.That(
GetDbAliases(page.Key).Any(a => a.Alias == "distributed-cache-alias"),
Is.True,
"URL aliases must be persisted to the database even when publishing under a distributed-cache-only notification publisher.");
});
}
/// <summary>
/// After publishing a document the notification handler must have written URL segments to
/// the database without any manual call to <c>CreateOrUpdateUrlSegmentsAsync</c>.