* Lowercase OpenAPI document name on registration to match AddOpenApi internal behaviour
AddOpenApi lowercases the document name when registering its keyed services, so
ReplaceOpenApiSchemaService must receive the same lowercased key or the lookup
throws. BackOfficeOpenApiDocumentBuilder now computes a normalised registration
name and uses it for all DI calls, while keeping DocumentName in its original
casing. ShouldInclude matches [MapToApi] case-insensitively to align with how
documents are registered, and the UI dropdown label falls back to DocumentName
(original casing) rather than the lowercased registration key.
AddUmbracoOpenApiDocument applies the same normalisation for its apiName parameter.
* Add regression tests for mixed-case OpenAPI document name registration
Covers the bug scenario where AddBackOfficeOpenApiDocument with a mixed-case
name and WithJsonOptions threw InvalidOperationException at startup, and verifies
that ShouldInclude matches [MapToApi] case-insensitively.
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>
Fix detail data request manager failing as soon as the number of items requested hits the UmbItemDataApiGetRequestController batch limit (40)
Co-authored-by: Paul Woodland <paul.woodland@pwnewmedia.com>
Fix detail data request manager failing as soon as the number of items requested hits the UmbItemDataApiGetRequestController batch limit (40)
Co-authored-by: Paul Woodland <paul.woodland@pwnewmedia.com>
* feat(media): add umb-thumbnail and configurable checkerboard background
Adds `umb-thumbnail` as the recommended alias of `umb-imaging-thumbnail`
(the original tag stays registered for backwards compatibility), and makes
the checkerboard background opt-out via the `--umb-thumbnail-background` CSS
custom property plus an `img` part for full styling control. Also fixes an
action-event listener leak in the thumbnail element, and adds a Storybook
story, an MDX guide, and component tests.
Closes#23177
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(media): address PR review on umb-thumbnail
- Rephrase the imaging-thumbnail JSDoc to a neutral alias statement instead of
a "prefer" wording that read like an undeclared deprecation.
- Guard the thumbnail tests so a renamed private field fails loudly rather than
producing vacuous assertions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(media): make umb-thumbnail canonical, deprecate umb-imaging-thumbnail
Invert the inheritance so the implementation lives on `UmbThumbnailElement`
(`umb-thumbnail`) and `UmbImagingThumbnailElement` (`umb-imaging-thumbnail`)
is the thin subclass. Removing the old tag is now just deleting one file.
The deprecated subclass emits a one-time `UmbDeprecation` warning (a
module-level guard avoids per-instance console spam) and carries a
`@deprecated` JSDoc, scheduled for removal in Umbraco 19.
Migrate the four internal consumers to `umb-thumbnail` so the deprecation
warning targets external code only, not our own.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(media): trim deprecated-alias thumbnail tests to a registration guard
The img part, checkerboard default and --umb-thumbnail-background override are
covered by thumbnail.element.test.ts and inherited from UmbThumbnailElement, so
re-asserting them on the umb-imaging-thumbnail subclass only tested inheritance.
Keep a single backwards-compat guard that the deprecated alias stays registered
and on the inheritance chain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(media): rename canonical thumbnail to umb-media-thumbnail; alias keeps @deprecated, no runtime warning
Per review (Niels): the forward-looking name is `umb-media-thumbnail`
(`UmbMediaThumbnailElement`), leaving room for non-media thumbnails later. The
implementation, CSS custom property (`--umb-media-thumbnail-background`), story,
guide and internal consumers all use the new name.
`umb-imaging-thumbnail` stays registered as a thin alias and keeps its
`@deprecated` JSDoc (IDE signal) but no longer emits a runtime UmbDeprecation
warning — both tags fly for now. Docs and comments lead with umb-media-thumbnail.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(core): annotate deprecation warnings with caller origin, suppress core noise in production
Deprecation warnings now state where the call most likely came from — Umbraco
core, an /App_Plugins package, or other custom code — by classifying the call
stack (first frame not under /umbraco/backoffice/ is the caller). This answers
the Codegarden feedback that you can't tell whose code triggered a warning.
In production builds, core-origin warnings are suppressed (a consumer can't act
on Umbraco's own code); package/external/unknown origins are always shown. The
production signal is the client build, not the server runtime mode — the latter
is unreliable since Umbraco Cloud defaults to BackofficeDevelopment. The new
umbIsProductionBuild() reads Vite's import.meta.env.PROD (substituted to true in
the shipped core bundle) and falls back to false outside a Vite build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(core): cleaner deprecation output and drop the throw for stack capture
Read new Error().stack directly instead of throwing and catching — the stack is
populated on construction. Annotate the warning with the resolved origin on its
own line rather than a bracketed prefix, and rely on the browser's native
expandable stack on console.warn for the full clickable trace instead of
printing one ourselves.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(core): trim inline comments in deprecation utils
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(core): address PR review on deprecation origin
- Clarify umbIsProductionBuild docs: in Vite dev import.meta.env is defined
(PROD false); the guard is for non-Vite contexts (tsc pass, web-test-runner).
- Strip query/fragment from parsed frame URLs so the external-origin label
can't carry ?/# noise.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DocumentHybridCacheStaleSetRaceTests came from the v17 PR #23169 and merged
forward into main (v18) unchanged, but on v18 IDatabaseCacheRepository renamed
GetContentSourceAsync -> GetDocumentSourceAsync and
GetContentSourceForPublishStatesAsync -> GetDocumentSourceForPublishStatesAsync.
The mock setups still referenced the v17 names, failing the build with CS1061.
Rename the two Moq setups to the v18 method names so the test compiles and the
mocks actually intercept the calls DocumentCacheService makes. v17 keeps the
Content* names and is unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Guard against cache poisoning from concurrency
* Resolve code review comments relating to tests.
* Avoid unnecessary second invalidation of memory cache generatio.
* Tighten the cache-generation guard.
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
* Display appropriate content type name in compositions dialog localised texts.
* Fix composition dialog translation typos and link references to the matching workspace
- fr: "sililaire" -> "similaire"
- it: "utlizzato" -> "utilizzato"
- es: remove duplicated "no puede no puede"
The reference list now builds its workspace edit href from the modal's
entityType instead of hardcoding document-type, so links resolve correctly
when the dialog is used for Media Types and Member Types.
* Integrate interaction memories into entity data picker
* Skip resetting unchanged data source API
Add an early-return guard in setDataSourceApi to avoid re-setting the same UmbPickerDataSource instance. Prevents rebuilding the modal token/route (which would close and reopen an open picker modal) on every re-render by only updating when the API actually changes.
* Add UmbEntityInputInteractionMemoryManager + implement across current inputs with memory
* clean up comment
* feat(elements): add value summary for Element Picker property editor
Adds a valueSummary extension so picked element names appear in collection
view columns. Includes a value-type constant, batch resolver, variant-aware
element, and a resolver unit test (11 cases).
* fix(elements): address PR review feedback on element picker value summary
- Call removeUmbControllerByAlias when removing a stale resolver so the
named observer controller is released from the element's controller list
- Call setData on existing resolvers when _value refreshes so renames are
reflected without recreating the resolver
- Remove redundant valueResolver re-export from resolver file (barrel handles it)
---------
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
* feat(ufm): add umbElementName UFM component
Adds a new UFM component that resolves Element display names from element
keys, mirroring the umbContentName component pattern. Uses the variant-aware
UmbElementItemDataResolver (via UmbElementItemRepository) for proper
culture/variant handling and (Untitled) fallback.
Also exports UmbElementItemDataResolver from the public
@umbraco-cms/backoffice/element entry point, matching the pattern used by
the documents package.
* fix(ufm): clear stale value and destroy resolvers in element-name element
Clear this.value when the render context produces no usable input, preventing
stale names from lingering when the context changes. Also destroy each
UmbElementItemDataResolver after getName() to avoid accumulating controller
registrations on the host element.
* Update src/Umbraco.Web.UI.Client/src/packages/ufm/components/element-name/element-name.element.ts
Co-authored-by: Andy Butland <abutland73@gmail.com>
* test(ufm): add umbElementName parsing test to marked-ufm.test.ts
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
* Block RTE: Implement unsupported block rendering
* Fixes `.ProseMirror-selectednode` focus ring
* Markup tidy-up
* Adds test for `umb-unsupported-rte-block`
* Block RTE: Reflect unsupported state as a host attribute
Replaces @state() + toggleAttribute() with @property({ reflect: true })
so Lit manages the 'unsupported' attribute sync during the update cycle,
avoiding constructor-time attribute access flagged by the linter.
Also removes the now-inert uui-text/uui-font classes from the block
wrapper div (backing styles were removed with UmbTextStyles).
* Adds JSDoc comment to `unsupported` property
* Block RTE: Extract #observeBlockViewProps() to reduce constructor size
Moves the block-view-props observer setup out of the constructor into a
dedicated #observeBlockViewProps() method, following the same pattern as
#observeData(). Reduces constructor from 123 to 64 lines (threshold: 70).
The `loaded`-signal test (added in #23167) built its host with
`UmbControllerHostElementMixin(HTMLElement)`, mirroring the older
`UmbBaseExtensionInitializer` tests. But `UmbExtensionInitializerBase`
requires a full `UmbElement` host, so the test failed `tsc` (TS2345)
under the root tsconfig. The product build excludes `*.test.ts`, so it
slipped through CI but breaks `npm run compile`/the editor.
Use `UmbElementMixin(HTMLElement)`, matching what production callers pass
(app/backoffice/preview elements are all UmbElements).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reconciles app.element.ts with #23020 (parallelized public extensions).
Kept the boot gate (await the app-entry-point initializer before routing)
and restored a blocking inline `await registerPublicExtensions()` instead
of the parallelized deferred form — a marginally slower but more robust
boot, identical to the release/17.5.0 fix (no empty-first-pass timing
reliance). extension-initializer-base.ts, the unit test, the acceptance
test and playwright config merge cleanly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* External login: wait for app-entry-points before the login provider decision
The backoffice boot stopped waiting for app-entry-point extensions to settle
before deciding which auth provider to use (regression introduced in #22522).
On a slow connection an externally registered authProvider (e.g. Umbraco ID)
is not registered yet when the login screen renders, so the user is dropped on
the local login instead of being redirected to the external provider.
- extension-initializer-base: `loaded` re-arms to `undefined` while a pass is in
flight and resolves to `true` unconditionally (including zero extensions), so
`.asPromise()` gates correctly and never hangs on a default install (which has
no app-entry-points) — the reason the await was removed in the first place.
- app.element: restore the awaited boot gate before routing.
Tests:
- Unit test for the `loaded` signal contract (zero extensions resolves; a late,
slow extension is awaited).
- Playwright acceptance test that deploys an app-entry-point registering an
authProvider after a delay and asserts it is offered on the login screen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(backoffice): guard the loaded-gate timing for permission loading
Add a test asserting the collection initializer's `loaded` does not open the
gate (`#loadedGuard` awaits it via `.asPromise()`, fronting private-extension
and user-permission loading) until the initially-registered extensions have
instantiated. Addresses the #22522 "user permissions resolved too late" concern
in writing; user-permission condition resolution itself lives in
UmbBaseExtensionInitializer (covered by base-extension-initializer.race.test.ts)
and is untouched by this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(backoffice): harden loaded signal + narrow acceptance test glob (review)
Address PR review feedback:
- extension-initializer-base: only the latest processing pass settles `loaded`
(monotonic pass id), so a slow earlier pass can't unblock waiters early when
the async observer overlaps passes; and use `Promise.allSettled` so a throwing
`instantiateExtension` can't leave `loaded` stuck at `undefined` (hanging the
boot gate) — failures are logged rather than swallowed.
- playwright.config: narrow the project glob to `**/*.spec.ts` so Playwright
doesn't try to load the App_Plugins `entry-point.js` ESM fixture as a test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* map settings to become a key-value-object
* implement type safety for block label ufm values
* added TODOs
* support variant value in Block Workspace Label
* External login: wait for app-entry-points before the login provider decision
The backoffice boot stopped waiting for app-entry-point extensions to settle
before deciding which auth provider to use (regression introduced in #22522).
On a slow connection an externally registered authProvider (e.g. Umbraco ID)
is not registered yet when the login screen renders, so the user is dropped on
the local login instead of being redirected to the external provider.
- extension-initializer-base: `loaded` re-arms to `undefined` while a pass is in
flight and resolves to `true` unconditionally (including zero extensions), so
`.asPromise()` gates correctly and never hangs on a default install (which has
no app-entry-points) — the reason the await was removed in the first place.
- app.element: restore the awaited boot gate before routing.
Tests:
- Unit test for the `loaded` signal contract (zero extensions resolves; a late,
slow extension is awaited).
- Playwright acceptance test that deploys an app-entry-point registering an
authProvider after a delay and asserts it is offered on the login screen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(backoffice): guard the loaded-gate timing for permission loading
Add a test asserting the collection initializer's `loaded` does not open the
gate (`#loadedGuard` awaits it via `.asPromise()`, fronting private-extension
and user-permission loading) until the initially-registered extensions have
instantiated. Addresses the #22522 "user permissions resolved too late" concern
in writing; user-permission condition resolution itself lives in
UmbBaseExtensionInitializer (covered by base-extension-initializer.race.test.ts)
and is untouched by this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(backoffice): harden loaded signal + narrow acceptance test glob (review)
Address PR review feedback:
- extension-initializer-base: only the latest processing pass settles `loaded`
(monotonic pass id), so a slow earlier pass can't unblock waiters early when
the async observer overlaps passes; and use `Promise.allSettled` so a throwing
`instantiateExtension` can't leave `loaded` stuck at `undefined` (hanging the
boot gate) — failures are logged rather than swallowed.
- playwright.config: narrow the project glob to `**/*.spec.ts` so Playwright
doesn't try to load the App_Plugins `entry-point.js` ESM fixture as a test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Adds UFM Member Name component
This is to support the standalone Member Picker values.
* fix(ufm): clear stale value on empty member picker; validate UDI-extracted GUIDs
* test(ufm): add umbMemberName parsing tests to marked-ufm.test.ts
Address PR review feedback:
- extension-initializer-base: only the latest processing pass settles `loaded`
(monotonic pass id), so a slow earlier pass can't unblock waiters early when
the async observer overlaps passes; and use `Promise.allSettled` so a throwing
`instantiateExtension` can't leave `loaded` stuck at `undefined` (hanging the
boot gate) — failures are logged rather than swallowed.
- playwright.config: narrow the project glob to `**/*.spec.ts` so Playwright
doesn't try to load the App_Plugins `entry-point.js` ESM fixture as a test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a test asserting the collection initializer's `loaded` does not open the
gate (`#loadedGuard` awaits it via `.asPromise()`, fronting private-extension
and user-permission loading) until the initially-registered extensions have
instantiated. Addresses the #22522 "user permissions resolved too late" concern
in writing; user-permission condition resolution itself lives in
UmbBaseExtensionInitializer (covered by base-extension-initializer.race.test.ts)
and is untouched by this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The backoffice boot stopped waiting for app-entry-point extensions to settle
before deciding which auth provider to use (regression introduced in #22522).
On a slow connection an externally registered authProvider (e.g. Umbraco ID)
is not registered yet when the login screen renders, so the user is dropped on
the local login instead of being redirected to the external provider.
- extension-initializer-base: `loaded` re-arms to `undefined` while a pass is in
flight and resolves to `true` unconditionally (including zero extensions), so
`.asPromise()` gates correctly and never hangs on a default install (which has
no app-entry-points) — the reason the await was removed in the first place.
- app.element: restore the awaited boot gate before routing.
Tests:
- Unit test for the `loaded` signal contract (zero extensions resolves; a late,
slow extension is awaited).
- Playwright acceptance test that deploys an app-entry-point registering an
authProvider after a delay and asserts it is offered on the login screen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>