diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/repository/detail/server-data-source/data-type-detail.server.request-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/repository/detail/server-data-source/data-type-detail.server.request-manager.ts index 03e70ef346..312a808616 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/repository/detail/server-data-source/data-type-detail.server.request-manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/repository/detail/server-data-source/data-type-detail.server.request-manager.ts @@ -9,7 +9,7 @@ import { } from '@umbraco-cms/backoffice/external/backend-api'; import { UmbManagementApiDetailDataRequestManager, - UmbManagementApiInflightRequestCache, + UmbManagementApiInFlightRequestCache, } from '@umbraco-cms/backoffice/management-api'; export class UmbManagementApiDataTypeDetailDataRequestManager extends UmbManagementApiDetailDataRequestManager< @@ -17,7 +17,7 @@ export class UmbManagementApiDataTypeDetailDataRequestManager extends UmbManagem UpdateDataTypeRequestModel, CreateDataTypeRequestModel > { - static #inflightRequestCache = new UmbManagementApiInflightRequestCache(); + static #inflightRequestCache = new UmbManagementApiInFlightRequestCache(); constructor(host: UmbControllerHost) { super(host, { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/detail/server-data-source/document-type-detail.server.request-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/detail/server-data-source/document-type-detail.server.request-manager.ts index ca22ff6cf1..1dcef4a61d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/detail/server-data-source/document-type-detail.server.request-manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/detail/server-data-source/document-type-detail.server.request-manager.ts @@ -9,7 +9,7 @@ import { } from '@umbraco-cms/backoffice/external/backend-api'; import { UmbManagementApiDetailDataRequestManager, - UmbManagementApiInflightRequestCache, + UmbManagementApiInFlightRequestCache, } from '@umbraco-cms/backoffice/management-api'; export class UmbManagementApiDocumentTypeDetailDataRequestManager extends UmbManagementApiDetailDataRequestManager< @@ -17,7 +17,7 @@ export class UmbManagementApiDocumentTypeDetailDataRequestManager extends UmbMan UpdateDocumentTypeRequestModel, CreateDocumentTypeRequestModel > { - static #inflightRequestCache = new UmbManagementApiInflightRequestCache(); + static #inflightRequestCache = new UmbManagementApiInFlightRequestCache(); constructor(host: UmbControllerHost) { super(host, { diff --git a/src/Umbraco.Web.UI.Client/src/packages/management-api/detail/cache.ts b/src/Umbraco.Web.UI.Client/src/packages/management-api/detail/cache.ts index 7d7cec8866..fab3fe2570 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/management-api/detail/cache.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/management-api/detail/cache.ts @@ -1,7 +1,8 @@ // Keep internal -interface UmbCacheEntryModel { +interface UmbDetailCacheEntryModel { id: string; data: DetailDataModelType; + timestamp: string; } /** @@ -10,7 +11,7 @@ interface UmbCacheEntryModel { * @template DetailDataModelType */ export class UmbManagementApiDetailDataCache { - #entries: Map> = new Map(); + #entries: Map> = new Map(); /** * Checks if an entry exists in the cache @@ -29,9 +30,10 @@ export class UmbManagementApiDetailDataCache { * @memberof UmbManagementApiDetailDataCache */ set(id: string, data: DetailDataModelType): void { - const cacheEntry: UmbCacheEntryModel = { + const cacheEntry: UmbDetailCacheEntryModel = { id: id, data, + timestamp: new Date().toISOString(), }; this.#entries.set(id, cacheEntry); diff --git a/src/Umbraco.Web.UI.Client/src/packages/management-api/detail/detail-data.request-manager.ts b/src/Umbraco.Web.UI.Client/src/packages/management-api/detail/detail-data.request-manager.ts index 37d501d991..cf33e0c4f5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/management-api/detail/detail-data.request-manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/management-api/detail/detail-data.request-manager.ts @@ -1,5 +1,5 @@ import { UMB_MANAGEMENT_API_SERVER_EVENT_CONTEXT } from '../server-event/constants.js'; -import type { UmbManagementApiInflightRequestCache } from '../inflight-request/cache.js'; +import type { UmbManagementApiInFlightRequestCache } from '../inflight-request/cache.js'; import type { UmbManagementApiDetailDataCache } from './cache.js'; import { tryExecute, @@ -21,7 +21,7 @@ export interface UmbManagementApiDetailDataRequestManagerArgs< update: (id: string, data: UpdateRequestModelType) => Promise>; delete: (id: string) => Promise>; dataCache: UmbManagementApiDetailDataCache; - inflightRequestCache: UmbManagementApiInflightRequestCache; + inflightRequestCache: UmbManagementApiInFlightRequestCache; } export class UmbManagementApiDetailDataRequestManager< @@ -30,7 +30,7 @@ export class UmbManagementApiDetailDataRequestManager< UpdateRequestModelType, > extends UmbControllerBase { #dataCache: UmbManagementApiDetailDataCache; - #inflightRequestCache: UmbManagementApiInflightRequestCache; + #inflightRequestCache: UmbManagementApiInFlightRequestCache; #create; #read; @@ -86,11 +86,13 @@ export class UmbManagementApiDetailDataRequestManager< const hasInflightRequest = this.#inflightRequestCache.has(inflightCacheKey); const request = hasInflightRequest - ? this.#inflightRequestCache.get(inflightCacheKey) + ? this.#inflightRequestCache.get(inflightCacheKey)?.requestPromise : tryExecute(this, this.#read(id)); if (!request) { - throw new Error(`Failed to create or retrieve 'read' request for ID: ${id} (cache key: ${inflightCacheKey}). Aborting read.`); + throw new Error( + `Failed to create or retrieve 'read' request for ID: ${id} (cache key: ${inflightCacheKey}). Aborting read.`, + ); } this.#inflightRequestCache.set(inflightCacheKey, request); diff --git a/src/Umbraco.Web.UI.Client/src/packages/management-api/inflight-request/cache.ts b/src/Umbraco.Web.UI.Client/src/packages/management-api/inflight-request/cache.ts index d1ba9a7441..b235aa5faa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/management-api/inflight-request/cache.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/management-api/inflight-request/cache.ts @@ -1,5 +1,11 @@ import type { UmbApiResponse } from '@umbraco-cms/backoffice/resources'; +interface UmbInFlightRequestCacheEntryModel { + key: string; + requestPromise: Promise>; + timestamp: string; +} + // Keep internal type RequestResolvedType = UmbApiResponse<{ data?: ResponseModelType }>; @@ -8,8 +14,8 @@ type RequestResolvedType = UmbApiResponse<{ data?: ResponseMo * @class UmbManagementApiInflightRequestCache * @template ResponseModelType */ -export class UmbManagementApiInflightRequestCache { - #entries = new Map>>(); +export class UmbManagementApiInFlightRequestCache { + #entries = new Map>(); /** * Checks if an entry exists in the cache @@ -28,7 +34,11 @@ export class UmbManagementApiInflightRequestCache { * @memberof UmbManagementApiInflightRequestCache */ set(key: string, promise: Promise>): void { - this.#entries.set(key, promise); + this.#entries.set(key, { + key, + requestPromise: promise, + timestamp: new Date().toISOString(), + }); } /** @@ -37,7 +47,7 @@ export class UmbManagementApiInflightRequestCache { * @returns {Promise> | undefined} - The cached promise or undefined if not found * @memberof UmbManagementApiInflightRequestCache */ - get(key: string): Promise> | undefined { + get(key: string): UmbInFlightRequestCacheEntryModel | undefined { return this.#entries.get(key); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/management-api/item/cache.ts b/src/Umbraco.Web.UI.Client/src/packages/management-api/item/cache.ts index 171af2c5ca..b1825f9643 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/management-api/item/cache.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/management-api/item/cache.ts @@ -1,7 +1,8 @@ // Keep internal -interface UmbCacheEntryModel { +interface UmbItemCacheEntryModel { id: string; data: ItemDataModelType; + timestamp: string; } /** @@ -10,7 +11,7 @@ interface UmbCacheEntryModel { * @template ItemDataModelType */ export class UmbManagementApiItemDataCache { - #entries: Map> = new Map(); + #entries: Map> = new Map(); /** * Checks if an entry exists in the cache @@ -29,9 +30,10 @@ export class UmbManagementApiItemDataCache { * @memberof UmbManagementApiItemDataCache */ set(id: string, data: ItemDataModelType): void { - const cacheEntry: UmbCacheEntryModel = { + const cacheEntry: UmbItemCacheEntryModel = { id: id, data, + timestamp: new Date().toISOString(), }; this.#entries.set(id, cacheEntry); diff --git a/src/Umbraco.Web.UI.Client/src/packages/management-api/server-event/global-context/server-event.context.ts b/src/Umbraco.Web.UI.Client/src/packages/management-api/server-event/global-context/server-event.context.ts index 1e08e907b2..cb426880a3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/management-api/server-event/global-context/server-event.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/management-api/server-event/global-context/server-event.context.ts @@ -94,8 +94,13 @@ export class UmbManagementApiServerEventContext extends UmbContextBase { }) .build(); - this.#connection.on('notify', (payload: UmbManagementApiServerEventModel) => { - this.#events.next(payload); + this.#connection.on('notify', (payload) => { + const event: UmbManagementApiServerEventModel = { + ...payload, + clientTimestamp: new Date().toISOString(), + }; + + this.#events.next(event); }); this.#connection diff --git a/src/Umbraco.Web.UI.Client/src/packages/management-api/server-event/global-context/types.ts b/src/Umbraco.Web.UI.Client/src/packages/management-api/server-event/global-context/types.ts index 5a0341345d..2ab17ee342 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/management-api/server-event/global-context/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/management-api/server-event/global-context/types.ts @@ -2,4 +2,5 @@ export interface UmbManagementApiServerEventModel { eventSource: string; eventType: string; key: string; + clientTimestamp: string; }