Compare commits

..
Author SHA1 Message Date
Laura NetoandGitHub df16c114b6 OpenApi: Lowercase document name on registration to match AddOpenApi internal behaviour (closes #23210) (#23212)
* 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.
2026-06-26 13:59:27 +02:00
fb1e16ff36 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:23:21 +02:00
Niels Lyngsø d889de6af0 Merge branch 'v17/dev' 2026-06-26 09:19:08 +02:00
d8f4342a86 Fix detail data request manager failing when items hit 40, making document unusable (#23164)
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>
2026-06-26 09:09:11 +02:00
774b2d4822 Fix detail data request manager failing when items hit 40, making document unusable (#23164)
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>
2026-06-26 09:08:14 +02:00
Niels LyngsøandGitHub 022439065f Block Workspace: avoid JS error if destroyed (#23200)
avoid JS error if Block Workspace Context was destroyed while awaiting a frame
2026-06-25 15:59:33 +02:00
Laura NetoandGitHub ba6ec7abcf Re-enable package validation (#23197) 2026-06-25 08:43:56 +00:00
Laura Neto 5d4d3a51ea Merge branch 'release/18.0' 2026-06-25 07:16:30 +01:00
Jacob Overgaard c6c5a9e7e6 Merge remote-tracking branch 'origin/v17/dev' 2026-06-24 11:51:40 +02:00
065e567f11 Media: Add umb-media-thumbnail with configurable checkerboard background (closes #23177) (#23178)
* 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>
2026-06-24 09:37:53 +00:00
58a1c15626 Deprecations: Annotate warnings with caller origin and suppress core noise in production (#23188)
* 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>
2026-06-24 09:29:21 +00:00
Laura Neto c087ce9fb5 Bump the version of the Umbraco.TheStarterKit to 18.0.0 in the UmbracoProject template 2026-06-24 11:23:37 +02:00
Jacob OvergaardandClaude Opus 4.8 cda880bb62 test(hybridcache): use v18 IDatabaseCacheRepository method names in stale-set race test
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>
2026-06-23 15:06:16 +02:00
Jacob Overgaard b3e6477df9 Merge remote-tracking branch 'origin/v17/dev' 2026-06-23 14:33:28 +02:00
Jacob Overgaard 8f3ff26005 Merge remote-tracking branch 'origin/release/18.0' 2026-06-23 14:32:19 +02:00
Jacob Overgaard 05f8158e4a Merge remote-tracking branch 'origin/release/17.5.0' into v17/dev 2026-06-23 14:29:24 +02:00
Jacob Overgaard 28b849f2d3 build(deps): bumps @umbraco-ui/uui to 1.18.1 2026-06-23 11:54:32 +02:00
Jacob Overgaard 8dd8820fa3 build(deps): bumps @umbraco-ui/uui to 2.0.0 2026-06-23 11:54:00 +02:00
ca7dcd5150 Published Cache: Guard against cache poisoning from a render-vs-publish race (#23169)
* 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>
2026-06-23 10:14:46 +02:00
Laura Neto 6b76230da5 Bump version to 18.0.0. 2026-06-23 09:38:59 +02:00
Kenn JacobsenandGitHub ceef53d624 Examine: Queue cold boot Examine reindexing at start-up, not at first request (Closes #22883) (#23181)
* Queue cold boot Examine reindexing at start-up, not at first request

* Review comments from Claude
2026-06-23 08:40:24 +02:00
Andy ButlandandGitHub 5bb53172aa ModelsBuilder: Avoid ObjectDisposedException in InMemoryModelFactory during shutdown (#23171)
* Guard EnsureModels against disposed lock on shutdown.

* Addressed code review comment.
2026-06-23 07:13:49 +02:00
Andy ButlandandGitHub aa9473131b Content Types: Show the correct type name (Media/Member Type) in the Compositions dialog (closes #23102) (#23118)
* 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.
2026-06-22 16:28:59 +01:00
Mads RasmussenandGitHub 35a3a2455c Entity Data Picker: Implement interaction memory + sync picker memory across all picker inputs (#23172)
* 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
2026-06-22 14:12:55 +00:00
Andy Butland 2e3628dad3 Bump version to 18.0.0-rc4. 2026-06-19 18:50:40 +02:00
Andy Butland 5a20452e7a Bump version to 17.5.0-rc3. 2026-06-19 18:44:26 +02:00
0e14ace89a Element Picker: Adds valueSummary display and value resolver (#23154)
* 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>
2026-06-19 14:11:12 +00:00
Andy Butland adeddeb148 Complete bump version to 17.5.0-rc2. 2026-06-19 15:51:10 +02:00
c9059c7b07 UFM: Add umbElementName component (#23162)
* 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>
2026-06-19 13:26:20 +00:00
Andy Butland 1ee24595d0 Fixed build error with integration tests. 2026-06-19 14:24:41 +02:00
Lee KelleherandGitHub ab8b8b48d4 Block RTE: Implement unsupported block rendering (closes #23071) (#23126)
* 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).
2026-06-19 13:08:00 +01:00
Jacob Overgaard 4ac8a397d0 Merge branch 'v17/dev'
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/content/content/types.ts
2026-06-19 13:58:25 +02:00
Jacob Overgaard feb1689848 Merge branch 'release/17.5.0' into v17/dev 2026-06-19 13:56:04 +02:00
Jacob OvergaardandClaude Opus 4.8 a14b908574 test(backoffice): fix host type in extension-initializer-base test
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>
2026-06-19 13:55:56 +02:00
Andy Butland 0f4b784c23 Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-06-19 13:40:22 +02:00
Andy Butland ebc0ef36f5 Merge branch 'v17/dev' 2026-06-19 13:40:09 +02:00
Jacob Overgaard 925d6bc430 Merge remote-tracking branch 'origin/release/17.5.0' into v17/dev 2026-06-19 13:37:44 +02:00
Jacob OvergaardandClaude Opus 4.8 acfaf23e43 Merge external-login entrypoint-race fix into v17/dev
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>
2026-06-19 13:35:21 +02:00
Jacob OvergaardandClaude Opus 4.8 cb23c84c3d External login: wait for app-entry-points before the login provider decision (#23167)
* 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>
2026-06-19 13:28:23 +02:00
Niels LyngsøandGitHub 7c1b907410 Block Workspace: Support variant properties and make '$settings' a key-value-object (Closes #23095) (#23123)
* 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
2026-06-19 11:26:18 +00:00
Niels Lyngsø 564ca0384b Squashed commit of the following:
commit cd132f44b1
Author: Niels Lyngsø <niels.lyngso@gmail.com>
Date:   Fri Jun 19 13:18:07 2026 +0200

    correct to use display: block;

commit a9ffa9f90b
Author: Andreas Lykke Borg <72602768+andreaslborg@users.noreply.github.com>
Date:   Mon Jun 15 20:56:51 2026 +0200

    Added css styling to block list and single to respect custom width
2026-06-19 13:25:17 +02:00
Niels Lyngsø fc3b13c85c Squashed commit of the following:
commit cd132f44b1
Author: Niels Lyngsø <niels.lyngso@gmail.com>
Date:   Fri Jun 19 13:18:07 2026 +0200

    correct to use display: block;

commit a9ffa9f90b
Author: Andreas Lykke Borg <72602768+andreaslborg@users.noreply.github.com>
Date:   Mon Jun 15 20:56:51 2026 +0200

    Added css styling to block list and single to respect custom width
2026-06-19 13:24:56 +02:00
9f633416b1 External login: wait for app-entry-points before the login provider decision (#23167)
* 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>
2026-06-19 12:11:28 +01:00
Lee KelleherandGitHub 91381604dd UFM: Add umbMemberName component (closes #22147) (#23165)
* 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
2026-06-19 09:48:51 +00:00
Jacob OvergaardandClaude Opus 4.8 c566dd0a71 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>
2026-06-19 11:35:26 +02:00
Jacob OvergaardandClaude Opus 4.8 ea78147657 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>
2026-06-19 11:19:39 +02:00
Andy ButlandandGitHub 0a5189e54a Content & Media: Enforce content type filters and allowed children/root rules when validating a create (#23163)
* Validate for content type filters on create document and media validation.

* Addressed code review feedback on tests.
2026-06-19 11:16:47 +02:00
Jacob OvergaardandClaude Opus 4.8 102e4aa80b 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>
2026-06-19 11:10:01 +02:00
Andy ButlandandGitHub 0bec947b8b Examine: Stream value sets to a single index during rebuild to reduce reindex peak memory (#23150)
* Stream value sets to a single index during rebuild to reduce reindex peak memory.

* Applied code review feedback.
2026-06-19 06:32:18 +02:00
Andy Butland 8bcd5990c2 Merge branch 'v17/dev' 2026-06-17 20:00:48 +02:00
Andy Butland d0e7ef0169 Merge branch 'release/17.5.0' into v17/dev 2026-06-17 19:31:46 +02:00
Jesper MadsenandJacob Overgaard e2cf205d34 Let the external login button show "sign in with {providername}" in languages (#23135) 2026-06-17 15:57:57 +02:00
Jesper MadsenandJacob Overgaard 1dfcd9332a Let the external login button show "sign in with {providername}" in languages (#23135) 2026-06-17 15:57:40 +02:00
Jesper MadsenandGitHub b2b45b016d Let the external login button show "sign in with {providername}" in languages (#23135) 2026-06-17 15:56:59 +02:00
Jacob Overgaard ef610c7d23 Merge remote-tracking branch 'origin/release/18.0' 2026-06-17 15:51:52 +02:00
Jacob Overgaard bf0270b244 build: deploy to npm through a template 2026-06-17 15:49:00 +02:00
Jacob OvergaardandClaude Opus 4.7 dc77f37129 Build: tag prerelease npm publishes with 'next' dist-tag (#22909)
* Build: tag prerelease npm publishes with 'next' dist-tag

Prereleases that flow through Deploy_Npm (e.g. 18.0.0-beta1) currently
land on the `latest` dist-tag, so a bare `npm install @umbraco-cms/backoffice`
resolves to an unstable build. Switch to `--tag next` when
NBGV_PrereleaseVersion is non-empty, leaving `latest` for stable releases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Build: address review feedback on npm prerelease dist-tag

- Add Build to Deploy_Npm dependsOn so stageDependencies.Build.A.outputs
  resolves explicitly (mirrors the Upload_API_Docs pattern).
- Pass npmPrereleaseVersion via env: instead of inline macro expansion in
  bash, so an unset variable won't be interpreted as command substitution.

* Build: source npmPrereleaseVersion via dependencies, not dependsOn

Switches the variable mapping from stageDependencies (which needs Build
in dependsOn) to dependencies.Build.outputs[...], matching the pattern
the stage's condition already uses on line 941. Avoids drawing a
redundant parallel arrow from Build to Deploy_Npm in the ADO stage
graph — Build is already in the ancestor chain via Deploy_NuGet.

* Build: align Deploy_Npm with Umbraco Deploy publish pattern

- Use stageDependencies form in variables: (dependencies.* only works in conditions).
- Source NBGV_PrereleaseVersionNoLeadingHyphen for a cleaner check.
- Replace echo >> .npmrc with npm config set --location=project.
- Collapse if/else into a tag=latest|next shell variable; single npm publish *.tgz.
- Drop unnecessary env: passthrough and npm init -y.

Per Ronald's feedback on PR #22909 — mirrors the Deploy pipeline's release stage.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-17 15:48:53 +02:00
Jacob OvergaardandClaude Opus 4.8 d84186061c fix(tests): point DomainCacheServiceTests mocks at GetAllAsync
IDomainService.GetAll was removed in #22629; DomainCacheServiceTests was
added later in #23084 against a stale base and still mocked the removed
method, breaking the Release build on release/18.0. Production
DomainCacheService already calls GetAllAsync, so update the four mock
setups to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 14:52:52 +02:00
Jacob Overgaard 87bc6522f1 build: deploy to npm through a template 2026-06-17 14:26:25 +02:00
Jacob OvergaardandClaude Opus 4.7 c300ebf94a Build: tag prerelease npm publishes with 'next' dist-tag (#22909)
* Build: tag prerelease npm publishes with 'next' dist-tag

Prereleases that flow through Deploy_Npm (e.g. 18.0.0-beta1) currently
land on the `latest` dist-tag, so a bare `npm install @umbraco-cms/backoffice`
resolves to an unstable build. Switch to `--tag next` when
NBGV_PrereleaseVersion is non-empty, leaving `latest` for stable releases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Build: address review feedback on npm prerelease dist-tag

- Add Build to Deploy_Npm dependsOn so stageDependencies.Build.A.outputs
  resolves explicitly (mirrors the Upload_API_Docs pattern).
- Pass npmPrereleaseVersion via env: instead of inline macro expansion in
  bash, so an unset variable won't be interpreted as command substitution.

* Build: source npmPrereleaseVersion via dependencies, not dependsOn

Switches the variable mapping from stageDependencies (which needs Build
in dependsOn) to dependencies.Build.outputs[...], matching the pattern
the stage's condition already uses on line 941. Avoids drawing a
redundant parallel arrow from Build to Deploy_Npm in the ADO stage
graph — Build is already in the ancestor chain via Deploy_NuGet.

* Build: align Deploy_Npm with Umbraco Deploy publish pattern

- Use stageDependencies form in variables: (dependencies.* only works in conditions).
- Source NBGV_PrereleaseVersionNoLeadingHyphen for a cleaner check.
- Replace echo >> .npmrc with npm config set --location=project.
- Collapse if/else into a tag=latest|next shell variable; single npm publish *.tgz.
- Drop unnecessary env: passthrough and npm init -y.

Per Ronald's feedback on PR #22909 — mirrors the Deploy pipeline's release stage.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-17 14:00:19 +02:00
7fdf9c12f3 Build: tag prerelease npm publishes with 'next' dist-tag (#22909)
* Build: tag prerelease npm publishes with 'next' dist-tag

Prereleases that flow through Deploy_Npm (e.g. 18.0.0-beta1) currently
land on the `latest` dist-tag, so a bare `npm install @umbraco-cms/backoffice`
resolves to an unstable build. Switch to `--tag next` when
NBGV_PrereleaseVersion is non-empty, leaving `latest` for stable releases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Build: address review feedback on npm prerelease dist-tag

- Add Build to Deploy_Npm dependsOn so stageDependencies.Build.A.outputs
  resolves explicitly (mirrors the Upload_API_Docs pattern).
- Pass npmPrereleaseVersion via env: instead of inline macro expansion in
  bash, so an unset variable won't be interpreted as command substitution.

* Build: source npmPrereleaseVersion via dependencies, not dependsOn

Switches the variable mapping from stageDependencies (which needs Build
in dependsOn) to dependencies.Build.outputs[...], matching the pattern
the stage's condition already uses on line 941. Avoids drawing a
redundant parallel arrow from Build to Deploy_Npm in the ADO stage
graph — Build is already in the ancestor chain via Deploy_NuGet.

* Build: align Deploy_Npm with Umbraco Deploy publish pattern

- Use stageDependencies form in variables: (dependencies.* only works in conditions).
- Source NBGV_PrereleaseVersionNoLeadingHyphen for a cleaner check.
- Replace echo >> .npmrc with npm config set --location=project.
- Collapse if/else into a tag=latest|next shell variable; single npm publish *.tgz.
- Drop unnecessary env: passthrough and npm init -y.

Per Ronald's feedback on PR #22909 — mirrors the Deploy pipeline's release stage.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-17 13:59:17 +02:00
Ronald BarendseandAndy Butland e2252a8634 Tests: Remove AutoFixture from the shipped Umbraco.Cms.Tests package (#23141)
Tests: Remove AutoFixture from Umbraco.Cms.Tests package
2026-06-17 09:50:01 +02:00
Ronald BarendseandGitHub 190e3d373a Tests: Remove AutoFixture from the shipped Umbraco.Cms.Tests package (#23141)
Tests: Remove AutoFixture from Umbraco.Cms.Tests package
2026-06-17 09:47:22 +02:00
dbecec3451 Cache: Populate the domain cache eagerly during start-up (#23139)
* Populate the domain cache eagerly during start-up

* Added extension method to encapsulate and test logic for skipping startup seeding.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-06-16 13:19:09 +00:00
Andy ButlandandGitHub d92e6bbeff Tiptap: Preserve wrapping link when editing an image (closes #23013) (#23019)
* Retain surrounding link when editing image details in rich text editor.

* Add JSDocs.
2026-06-16 11:06:45 +01:00
e56ddcc3f9 Tiptap RTE: Fixes toolbar button active state not updating on collapsed-cursor mark toggle (closes #22907) (#22929)
* update tiptap event listneres

* Tiptap: Add regression test for toolbar button active state on collapsed-cursor toggle (closes #22907)

Tests verify the `transaction` listener wiring that fixes the stored-mark active-state bug.

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-06-16 09:56:42 +00:00
Laura NetoandGitHub 84a1ca8335 SonarCloud: Improve workflow (#23080)
* SonarCloud: allow unit test failures without failing the analysis

Test failures should not block SonarCloud analysis - coverage data is
still collected by dotnet-coverage regardless of test outcome. The
regular CI pipeline is the correct gate for test pass/fail.

* SonarCloud: install Java 21 explicitly and skip JRE provisioning

- Add actions/setup-java@v5 (temurin-21) so JAVA_HOME always points to Java 21
- Pass sonar.scanner.skipJreProvisioning=true in the begin command since Java 21 is installed explicitly, removing the need for the scanner to download a JRE at runtime

* SonarCloud: clear SONARQUBE_SCANNER_PARAMS after begin

Prevents the End analysis step from re-applying sonar params that begin already wrote to the analysis config, eliminating the "Ignoring property from env variable" warning.

* SonarCloud: always cancel in-progress runs on new push

* TEMP: add failing test to verify pipeline resilience — revert before merge

* Revert "TEMP: add failing test to verify pipeline resilience — revert before merge"

This reverts commit 828a7510cb.

* Revert "SonarCloud: clear SONARQUBE_SCANNER_PARAMS after begin"

This reverts commit 1911b65db1.

* Make SonarCloud workflow resilient to build and test failures

* Fix inaccurate warning message when unit tests fail

* Revert build step resilience, keep test failure warning

* Improve test failure warning with coverage file check

* Temporary: add failing test to verify SonarCloud workflow resilience

* Revert "Temporary: add failing test to verify SonarCloud workflow resilience"

This reverts commit 71ecd61034.
2026-06-16 09:31:50 +00:00
fb8c3b19ce Backoffice: Fix core circular import (fetchAllPages) breaking the test check (#23133)
Backoffice: Move fetchAllPages into the repository module to break a core circular import

#22765 added the offset pagination helper `fetchAllPages` under
`@umbraco-cms/backoffice/utils`, but its contract is expressed entirely in
repository-owned types (`UmbDataSourceResponse<UmbPagedModel<T>>`). That made
`utils` import `repository` while `repository` already imports `utils`,
introducing a 17th core bidirectional module import and tripping
`check:module-dependencies` (threshold 16) — failing the `test` job on every
open PR.

Relocate the helper (and its test) into the `repository` module, which
legitimately owns those types, and export it from
`@umbraco-cms/backoffice/repository`. The sole consumer
(UmbLanguageCollectionRepository) already imports from that module. Core
bidirectional imports are back to 16.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 09:51:36 +01:00
Andy Butland b940b27ad2 Updated OpenApi.json. 2026-06-16 10:09:54 +02:00
Andy Butland d416d352e0 Merge branch 'v17/dev' 2026-06-16 09:26:33 +02:00
Andy ButlandandGitHub 7a7aadffe5 User Groups: Clear the user group cache when a language is deleted (closes #23121) (#23131)
* Ensure user group cache is cleared on language delete.

* Apply code review feedback.
2026-06-16 08:47:46 +02:00
Andy ButlandandGitHub 0ac6e8500a Background Jobs: Recover cache-sync and server-touch jobs when a database call hangs (closes #23106) (#23119)
* Recover cache-sync job if database Sync() hangs.

* Apply also to TouchServerJob.

* Addressed code review comments.

* Added debug logging to allow monitorring of job runs.

* Added tests verifying that jobs resume after an inflight call completes.
2026-06-16 08:01:14 +02:00
4c35c0c2e9 Management API: Add endpoints to sort the children of a document or media item by a system field (#23077)
* Add endpoints for sorting documents and media by system fields.

* Addressed code review feedback.

* Persist sort-children-by-field with a single set-based update.

* Addressed second round of code review feedback.

* DRYed up similar code, improved comments.

* Split tests into individual class files

* Added test for combined sort of invariant and variant children.

* Addressed further code review feedback.

* Include test scenario from #23128 for SortChildren()

* Renamed children authorizer as it is generic, not specific for sorting - and updated XML docs accordingly

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-06-16 05:29:47 +00:00
Nhu DinhandGitHub a15d340608 E2E: QA Added acceptance tests for published element extensions (#23030)
* Added api helper for creating element type with compositions

* Added api helper for creating template with displaying element picker

* Added tests for published element extensions

* Make tests run in the pipeline

* Fixed suggestions

* Fixed comment

* Reverted npm command
2026-06-16 03:29:45 +00:00
Andy ButlandandGitHub de47e0b1f7 Content/Media: Reload content on Sort to avoid data loss with partially loaded entities (closes #23120) (#23128)
Ensure calling sort for content or media with partially loaded entities doesn't lose the unloaded data on persistence.
2026-06-15 19:31:34 +02:00
Andy Butland 969ae87798 Added TODO to adjust the ScheduledPublishingSettings.AlignToClock default to true. 2026-06-15 16:39:23 +02:00
Andy Butland 37e2458475 Merge branch 'release/18.0' of https://github.com/umbraco/Umbraco-CMS into release/18.0 2026-06-15 16:20:46 +02:00
Andy Butland 2461853b11 Published Cache: Fix multi-site domains falling back to the first root node after restart (#23084)
* Prevent empty domain cache during concurrent initialization.

* Addressed code review comments and added further comment to the code.

* Use Lock object.
2026-06-15 16:20:11 +02:00
Andy Butland fe3318ef79 Published Cache: Fix multi-site domains falling back to the first root node after restart (#23084)
* Prevent empty domain cache during concurrent initialization.

* Addressed code review comments and added further comment to the code.

* Use Lock object.
2026-06-15 16:19:24 +02:00
Andy ButlandandGitHub 828e359666 Languages: Page through to load all configured languages (#22765)
* Ensure all languages are retrieved handling rare (theoretical?) case where the number of languages exceeds the default page size.

* Addressed code review feedback.

* Addressed further code review feedback.
2026-06-15 16:17:30 +02:00
a5b7e0dac1 Scheduled publishing: Add configurable period and optional clock-aligned scheduling (#23127)
* Add configurable period for scheduled publishing task with optional clock alignment.

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Addressed code review comments.

* Clarified the maths, improved comments and test coverage.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-15 13:48:34 +00:00
Nicklas KramerandGitHub 9fe9469e3a Integration Tests: Adjusting Status Codes for Failing Tests (#23125)
Adjusting expected status codes
2026-06-15 15:39:47 +02:00
16c97d613f Elements: Invalidate the id/key map when an element container is deleted (closes #23072) (#23074)
* Refresh the element container cache on delete to ensure the id/key map is invalidated.

* Rename and additional asserts in test.

* Use a dedicated refresher for element container id/key map eviction

Routing container-delete invalidation through ElementCacheRefresher cleared
the entire elements cache on every payload, so deleting a container triggered
a full clear even though no element data changed (and a second clear on top of
the ElementTreeChangeNotification refresh when the container held elements).

Add a dedicated ElementContainerCacheRefresher whose only job is to evict the
container's IIdKeyMap entry, and route EntityContainerDeletedNotification
through it instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Addressed code review feedback.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:16:31 +02:00
Nhu DinhandGitHub 5a6b18307d E2E: QA Added acceptance tests for broken publish path in legacy routing (#23090)
* Added ui helper for does not contain text

* Added constant for cannot be routed in content

* Added ui helper for verify document does not contain link

* Added api helper for unpublish document and publish chain of document

* Added api helper for updating document type

* Added tests for handling broken publish path in backoffice

* Added tests for handling broken publish path in delivery API

* Make tests run in the pipeline

* Clean up

* Fixed comments

* Reverted npm command
2026-06-15 09:55:26 +00:00
Nhu DinhandGitHub 3ee7b142b3 E2E: Fixed failing acceptance tests for user group, backoffice search and content picker (#23108)
* Updated backoffice search element tests to match the test helper changes

* Added step to delete user group before deleting language

* Updated tests for element folder permission due to recent changes

* Fix failing tests for content picker and element with element picker due to UI changes
2026-06-15 08:57:13 +00:00
Andy Butland ae92b0b0a9 Fixed failing unit test. 2026-06-15 07:07:51 +02:00
Andy Butland 8503762431 Merge branch 'v17/dev' 2026-06-15 06:49:06 +02:00
Andy ButlandandGitHub 86abc3528d Request Logging: Avoid forcing a session store load when resolving the session id for logging (closes #23082) (#23083)
* Guard read of session ID for log enrichment by presence of session cookie.

* Renamed tests.

* Add configurable option for session ID logging, retaining backward compatibility but giving options to skip session Id logging or use a cookie hash.
2026-06-15 06:47:59 +02:00
Andy Butland 97a005e709 Merge branch 'release/18.0' 2026-06-15 06:42:11 +02:00
Andy Butland 30b4370044 Merge branch 'v17/dev' 2026-06-15 06:40:59 +02:00
Andy Butland cffac2a990 Dependencies: Update MessagePack to 3.1.7 to address security advisories (#23113)
Update MessagePack dependency to 3.1.7.
2026-06-15 06:37:13 +02:00
Andy Butland 7433641348 Dependencies: Update MessagePack to 3.1.7 to address security advisories (#23113)
Update MessagePack dependency to 3.1.7.
2026-06-15 06:35:25 +02:00
Andy ButlandandGitHub c45b12ec58 Dependencies: Update MessagePack to 3.1.7 to address security advisories (#23113)
Update MessagePack dependency to 3.1.7.
2026-06-15 06:34:57 +02:00
Kenn JacobsenandGitHub 6883c6fcfd Tags: Expand ITagService to handle Elements (#23117) 2026-06-15 06:28:52 +02:00
Andy ButlandandGitHub 22c4bc7835 Package migrations: Surface a failed unattended package migration as a boot failure instead of getting stuck on the upgrade screen (#23114)
* Surface a package migration exception as a boot failure, avoiding being stuck in an upgrading state.

* Addressed code review feedback.

* Fix failing integration tests.
2026-06-15 11:58:58 +09:00
Andy ButlandandGitHub 1e82376420 Skills: Add umb-release-notes skill for improving generated release notes (#23112)
* Add skill to help with improving the generated GitHub release notes.

* Addressed skill review feedback.
2026-06-15 11:41:57 +09:00
Andy Butland e8586493e2 Merge branch 'v17/dev' 2026-06-13 15:42:41 +02:00
d5d0ce68aa Property editors: Add configuration and validation of allowed types for element picker, document picker, media picker (#23026)
* add allowed type for element picker

* update validation and unit test

* remove redundant code

* update tests name

* revert code GetReferences

* remove un-using code and add more check value

* remove redundant param

* add allowed type for content picker, update validation

* add min max validation into element and its unit test

* update media picker validation

* split validation runner into other class

* update SystemTextJsonSerializerBase back to old code

* update unit tests

* Resolved some code warnings.

* Remove accidentally committed file

* Introduce ITypedValidator and obsolete ITypeJsonValidator to better reflect validators that may or may not contain JSON editor values.

* Extraced ParseAllowedContentTypeKeys into a common helper.

* Aligned parameters on AllowedTypeValidator.

* Align parsing of allowed type Ids on client between document and media pickers.

* Restored validation of media where provided key can't be retrieved.

* Aligned document, media and element configuration labels and weights.

* Added additional unit tests.

* Addressed code review comments.

* Resolved further code warnings and code tidy.

* Resolve potential binary breaking change concern with obsolete ITypedJsonValidator.

* Reuse shared DocumentTypePicker for picker allowed-types config.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-06-13 13:30:34 +00:00
Zeegaan 764d4eb1d7 bump version 2026-06-11 14:02:32 +09:00
de61491093 Tests: Update DomainCacheServiceTests to mock GetAllAsync instead of removed GetAll (#23097)
update unit tests for domain cache service

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-06-10 12:14:01 +02:00
Mads RasmussenandGitHub aa854da3f4 Backoffice: Pre-expand tree to target entity when opening Duplicate and Move To modals (closes #22015) (#23063)
* Support tree expansion in generic Duplicate To modal

* Add expansion prop to tree picker modal types

* Apply expansion from data to picker context

* move to action: populate tree picker expansion with ancestors

* Pass tree expansion to duplicate document modal

* Extract ancestor fetching into private method

* Use UmbDocumentTreeRepository directly

* Exclude self from ancestor results

* make name more explicit

* Guard ancestor fetch and simplify expansion

* Only set treeExpansion when ancestors exist

* fix type issues

* Parallelize ancestor and pickable filter fetch

* Use getter for treeExpansion; remove unused imports
2026-06-09 16:53:37 +02:00
Jacob Overgaard deafc20db9 Merge remote-tracking branch 'origin/v17/dev' 2026-06-09 13:20:53 +02:00
Niels LyngsøandGitHub 28cdbe5317 TipTap: Let the stylesheet load parallel to tiptap-extensions (#23024)
do not await stylesheets to be loaded before extensions
2026-06-09 11:14:49 +00:00
6d1487ef4e Global Search: Localize global search manifest labels and names (#23091)
* add localization for search manifest

* only localization for label

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-06-09 08:35:15 +00:00
Jacob Overgaard 46aa184e10 Merge remote-tracking branch 'origin/v17/dev' 2026-06-09 10:31:49 +02:00
3dbd4baefe Backoffice Search: Batch the ancestors lookup for search results to avoid exceeding the maximum URL length (closes #23032) (#23048)
* Ensure requests to fetch ancestors after retrieving search results are batched to avoid a single query exceeding the maximum URL length.

* Guard against undefined ancestor entries from a failed batch

batchTryExecute resolves each chunk via tryExecute, which never rejects, so
a per-chunk failure comes back as a fulfilled result carrying an error and
leaves an undefined hole in the amalgamated data without surfacing an error.
Detect that before mapping and return an explicit error instead of throwing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Assert ancestor id uniqueness and silence direct-api lint rule

Strengthen the batching tests to assert every search-result id is requested
exactly once (Set size), not just that the total count matches. Add the
no-direct-api-import disable on the controller's api callback, matching the
existing url data sources, since the call is wrapped by the controller.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Addessed Codescene warnings.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 10:31:37 +02:00
Jacob Overgaard c1ba303fdc Merge remote-tracking branch 'origin/v17/dev' 2026-06-09 10:30:22 +02:00
Andy ButlandandGitHub fa5dd209c1 Tags: Fix null reference error in tags input on render (closes #23044) (#23049)
Fix intermittent null reference exception in tags element.
2026-06-09 10:29:27 +02:00
Andy ButlandandGitHub 4cc4acee62 Published Cache: Fix multi-site domains falling back to the first root node after restart (#23084)
* Prevent empty domain cache during concurrent initialization.

* Addressed code review comments and added further comment to the code.

* Use Lock object.
2026-06-07 15:35:38 +02:00
Andy ButlandandGitHub 5dd28e7a13 Tests: Fix failing Management API integration tests (closes #23076) (#23081)
* Include currently missing management API tests in the CI build.

* Fixed failing tests.

* Revert the pipeline updates.

* Addressed code review feedback.
2026-06-07 08:40:23 +02:00
Andy Butland d0fc7dc8a0 Tiptap RTE: Ignore no-op transactions in onUpdate to prevent phantom dirty state (closes #22767) (#22781)
Ignore Tiptap no-op transactions in onUpdate to prevent phantom dirty state.
2026-06-05 15:56:23 +02:00
Niels LyngsøandGitHub 87b24912c7 V18: Beta UI adjustments (#22869) 2026-06-05 15:10:54 +02:00
62663d9573 Runtime Cache: Fix IAppPolicyCache.ClearByKey intermittently failing to clear cached items (closes #23064) (#23068)
* Prevent ClearByKey leaving stale runtime cache items.

* Lowered loop timer.

* Clarified code comment.

* Improve assertions and comments in tests.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-06-05 09:23:26 +02:00
b582f9d2ef Dependencies: Upgrade Examine to 3.8.0 (#23075)
Upgrade Examine to 3.8.0

Co-authored-by: Simon Gibbs <sgibbs@qmu.ac.uk>
2026-06-05 06:59:11 +02:00
a3424eb40d Dependencies: Upgrade Examine to 3.8.0 (#23075)
Upgrade Examine to 3.8.0

Co-authored-by: Simon Gibbs <sgibbs@qmu.ac.uk>
2026-06-05 06:58:20 +02:00
Andy Butland f6c70e8429 Bump version to 18.0.0-rc3. 2026-06-05 06:46:44 +02:00
Andy Butland 68d03ae7c4 Merge branch 'release/18.0' 2026-06-05 06:42:24 +02:00
Laura NetoandGitHub 1dbcf1037a Delivery API - Open API: return inline {} schema for unconstrained property types (#23066)
* Delivery API: return inline {} schema for unconstrained property types

ContentTypeSchemaTransformer now checks the raw STJ schema via JsonSchemaExporter before
calling GetOrCreateSchemaAsync. STJ generates boolean true for unconstrained types (JsonNode,
object, types with custom converters), which the pipeline converts to {}. When the raw schema
is true, an inline {} is returned without registering a named component - a named component
adds no value and misleads API consumers into thinking a concrete model shape exists.

* Delivery API: add Plain JSON property to contract test sample types

Adds a Plain JSON property to the sample article page content type used by the OpenAPI contract
tests. This exercises the unconstrained-type fix: the property should appear as inline {} in the
schema, not as a named JsonNode component. Updates the expected contract to reflect the new
property.

* Re-generate typed-schemas-with-sample-types.json

For some reason the previous change got formatted differently, so it was displaying more changes than it should.

* Simplify comments

* Delivery API: guard unconstrained type check with JsonTypeInfoKind.None
2026-06-04 17:01:49 +02:00
Andy ButlandandGitHub 27909ed18e Elements: Hide element actions from the document notifications dialog (closes #23053) (#23059)
Remove element actions from the notification dialog.
2026-06-04 14:57:32 +02:00
Jacob Overgaard 91c9b79926 Merge remote-tracking branch 'origin/v17/dev' 2026-06-04 10:41:08 +02:00
ad90db8b38 Performance: Coalesce concurrent tree data requests (Management API client) (#23021)
* perf(tree): coalesce concurrent identical tree data requests

The tree data request manager hit the network on every call, so multiple
concurrent consumers (sidebar tree, breadcrumb structure, pickers) each
fetched the same data independently — e.g. three identical tree/document/root
requests per document-workspace load.

Apply the existing UmbManagementApiInFlightRequestCache (already used by the
item and detail request managers) to the tree request manager via a shared
static cache, coalescing concurrent identical root/children/ancestors/siblings
calls into a single in-flight request, cleared on settle (in-flight only, so
no stale-cache risk). The document tree opts in; other trees are unchanged
until they pass a cache.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(tree): cover request coalescing; address review feedback

- Add focused tests: concurrent identical root requests share one call,
  the in-flight entry is cleared on settle, and no cache means no coalescing.
- Build the cache key lazily (only when a cache is wired) so non-opted-in
  trees keep the original lightweight path.
- Constrain the #coalesce generic to drop the cast on cache.set.
- Document the new inflightRequestCache arg; trim the comment to one line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 10:40:58 +02:00
Erik-Jan WestendorpandAndy Butland 8e3b821a55 Localization: Add Dutch translations for create and delete actions (#23039)
Update nl.ts
2026-06-04 08:37:53 +02:00
Erik-Jan WestendorpandGitHub 5ade6ae6ec Localization: Add Dutch translations for create and delete actions (#23039)
Update nl.ts
2026-06-04 08:37:12 +02:00
Andy Butland 7ca8d3d872 Merge branch 'v17/dev' 2026-06-04 07:59:53 +02:00
Andy ButlandandGitHub 8ac989c4e3 Data Types: Tolerate invalid configuration when determining the editor value storage type (closes #23057) (#23058)
* Tolerate invalid data type configuration when getting the editor value storage type.

* Add logging in case of error.

* Resolve warning.

* Removed exception from warning (it's not useful).

* Log an error instead of a warning.
2026-06-04 14:38:21 +09:00
Andy Butland fceb2f421f Merge branch 'v17/dev' 2026-06-04 06:45:50 +02:00
Andy Butland 54827c4c92 Background Jobs: Resolve server role so recurring jobs run when no application URL is configured (#23033)
Resolve server role when no application URL is configured.
2026-06-04 06:44:51 +02:00
Andy Butland 89baa9482b Background Jobs: Resolve server role so recurring jobs run when no application URL is configured (#23033)
Resolve server role when no application URL is configured.
2026-06-04 06:40:00 +02:00
Andy ButlandandGitHub 3913a61b74 Background Jobs: Resolve server role so recurring jobs run when no application URL is configured (#23033)
Resolve server role when no application URL is configured.
2026-06-04 06:37:08 +02:00
Andreas ZerbstandGitHub 245bc336a5 E2E: QA: Add acceptance test for backoffice search (#22730)
* Added tests

* Cleaned up

* Updated command

* Fixes based on comments

* Split tests

* Updated helpers

* Fixed constant helper after merge

* Use correct helper

* Cleaned up

* Update smokeTest command in package.json
2026-06-03 19:49:12 +00:00
Andy Butland c5efd65e23 Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-06-03 18:49:28 +02:00
Andy Butland cb9ac904f6 Merge branch 'v17/dev' 2026-06-03 18:49:12 +02:00
Laura NetoandGitHub cc38e5724b SonarCloud: Simplify to single workflow, skip fork PRs (#23054) 2026-06-03 18:37:07 +02:00
Lee KelleherandGitHub 90bedcd42e Menu Structure: Guard against use-after-destroy in async structure request (#23055)
* Menu Structure: Guard against use-after-destroy in async structure request

When navigating to a trashed item, the IS_NOT_TRASHED condition initially
permits the standard menu structure context, which is then destroyed once the
workspace confirms the item is trashed. The in-flight async #requestStructure()
could resume after destruction and call setValue() on a completed subject,
throwing "_subject is undefined".

Guard the state mutations with the framework's existing _host-cleared-on-destroy
signal, and handle the previously fire-and-forget #requestStructure() promises so
a teardown mid-request is silently abandoned rather than surfacing as an uncaught
rejection. Applied to both the variant and non-variant menu structure base
contexts.

* Menu Structure: Make #requestStructure non-throwing instead of catching at call sites

Per PR review feedback: replace the blanket .catch(() => {}) wrappers with
early returns inside #requestStructure(). The _host guard already prevents
post-destroy state mutation; the throws only fire for can't-happen missing
observable states and were producing unhandled rejections with no caller
able to act on them.

* Added console warning, if the host is still available
2026-06-03 18:32:29 +02:00
Lee KelleherandGitHub c54189aa90 Block Grid: Guard validator against torn-down manager on navigation (#22852)
* Block Grid: Guard validator against torn-down manager on navigation

The form-control mixin's updated() hook runs validators when the element
re-renders during teardown. If navigation has already disposed _manager,
checkBlockTypeConfigurationValidity would throw "Cannot read properties
of undefined (reading 'getContentTypeKeyOfContentKey')".

Early-return as valid when the manager is gone and use optional chaining
on the per-entry lookup as a safety net.

* Removed optional chaining of `_manager`

As `_manager` has already been checked.

* Reverting the `_manager` optional chaining

As TypeScript compiler doesn't like it, (inside the `filter` callback).
2026-06-03 15:29:41 +02:00
88ec0a248f Media: Restore friendly naming of uploaded media items (closes #22989) (#22998)
* Update uploaded media file name to a friendly name.

* Correct test description for acronym handling.

The case JUST-A-FILE.jpg verifies all-uppercase words are preserved
as acronyms, not that lowercase words get lowercased.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Match server-side StripFileExtension semantics in toFriendlyName.

The TypeScript helper previously delegated to getFileExtension, which
diverges from the C# StripFileExtension on two edge cases:
- a trailing dot ("file.") is stripped by the server but not the client
- an "extension" containing whitespace is preserved by the server but
  stripped by the client

Inlined a stripFileExtension helper that mirrors the C# rules exactly,
making the "keep in sync" cross-reference accurate. Added tests for both
divergent cases and replaced the contrived leading/trailing whitespace
test with a realistic interior-whitespace case.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Add parity test for trailing-whitespace extension span.

Restores the '  spaced-name.jpg  ' case as a parity test against
StripFileExtension's "extension containing whitespace is preserved"
rule. Output is 'Spaced Name.Jpg' (Jpg title-cased, matching the
server's TextInfo.ToTitleCase behaviour on the now-unstripped extension).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Handle getContext rejection in ensureMediaNameFromFile.

getContext rejects on timeout when the dataset context never resolves;
callers used void ensureMediaNameFromFile(...) so an unhandled rejection
would bubble. Catch the rejection and treat it as an absent context.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-03 12:37:49 +01:00
Jacob Overgaard 7158aec145 Merge branch 'release/18.0' 2026-06-03 13:06:55 +02:00
Laura NetoandGitHub 214fd03241 OpenAPI: Disable XML documentation source generator (closes #23018) (#23045)
Disable OpenAPI XML documentation source generator

Due to the amount of XML documentation in this solution, the OpenAPI XML documentation source generator produces too many lines of code in a single method (GenerateCacheEntries), which causes a StackOverflowException when running on IIS. The fix disables the analyzer globally via Directory.Build.props.
2026-06-03 12:28:51 +02:00
a3f65b2920 Redirects: Adding notification for redirect save and deletion (#22985)
* Creating notification objects and status

* Adjusting service and tracker to support cancelable notifications

* Adding Operation Status Results to base controller.

* Adding notification support to the delete controller.

* Integration tests

* Changes in accordance to CR

* Changes in accordance to code review

* Fixed further use of obsolete methods in tests.

* Added comment explaining why messages on create or update cancellation are suppressed.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-06-03 09:37:31 +00:00
Jacob OvergaardandGitHub 787f66be3d Dependencies: Bumps @umbraco-ui/uui from 2.0.0-rc.1 to 2.0.0-rc.2 (#23052)
build(deps): bumps @umbraco-ui/uui from 2.0.0-rc.1 to 2.0.0-rc.2
2026-06-03 09:00:01 +00:00
Erik-Jan WestendorpandAndy Butland cd23fc75c5 Localisation: Translate the "Library" section header into other languages (#23043)
* Translate library to Dutch and Spanish

* Add translations for other cultures.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-06-03 09:36:43 +02:00
230b5db528 Localisation: Translate the "Library" section header into other languages (#23043)
* Translate library to Dutch and Spanish

* Add translations for other cultures.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-06-03 07:35:06 +00:00
Nhu DinhandGitHub 2372c40056 E2E: QA Added acceptance tests for element folder permission (#22905)
* Added constant setting for element folder permission

* Added api helper for element folder

* Added api helper for user group with element folder permission

* Added ui helper for element folder permission in user group

* Added tests for element folder permission

* Added locator for restore element

* Added api helper for Combined element + element folder permission methods

* Added more tests for restore element folder

* Make tests run in the pipeline

* Fixed comments

* Reverted npm command
2026-06-03 03:19:02 +00:00
75d2b0129d E2E: QA Added acceptance tests for Element Type settings (#23005)
* Updated createEmptyElementType

* Updated tests due to test helper changes

* Added ui helper for not applicable message for element type

* Added tests for showing message for non-applicable Element Type settings

* Added tests for preventing disabling isElement when elements of that type exist

* Make tests run in the pipeline

* Fixed comments

* Update tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/DocumentType/DocumentTypeSettingsTab.spec.ts

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>

* Reverted npm command

---------

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-06-03 03:13:52 +00:00
Jacob Overgaard b410e060b6 Merge remote-tracking branch 'origin/v17/dev' 2026-06-02 16:32:14 +02:00
Lee KelleherandGitHub 3e22733081 Document Recycle Bin: Checks user permission for Document "Read" (#23041)
* Adds conditions to Document Recycle Bin

that the user must have "Read" permission.

* Directly imports Media Recycle Bin condition

this will remove an extra fetch request.
2026-06-02 16:31:51 +02:00
Laura NetoandGitHub a86777a8f2 Build: Add SonarCloud CI workflow (#22960)
* Add SonarCloud CI workflow

Adds a manual-dispatch GitHub Actions workflow for SonarQube Cloud
analysis (build, unit test coverage, scan). Moves file_header_template
and SA1636/SA1633 suppression from .editorconfig comments and
.globalconfig into the active .editorconfig .NET language conventions
section, removing the duplicated suppression from .globalconfig.

* Remove branch filter from pull_request trigger in SonarCloud workflow

Runs analysis on all PRs regardless of target branch.

* Adjust sonarcloud gh action based on feedback

* Add .sonarqube to .gitignore

* Attempt to split build and analysis in order to be able to run in PRs from forks

* Adjust SonarCloud workflows

* Rename SonarCloud workflows to reflect their actual purpose

* Remove sonar.coverage.exclusions

* Include .github in sonar analysis

* Include build directory in sonar analysis

* Apply sonarcloud workflow fixes from test branch

* Remove setup-dotnet step from upload workflow

* Use default branch from context instead of hardcoded main in analysis workflow

* Update checkout action to v6 in upload workflow

* Add actions: read permission to upload workflow

* Enable SCM integration in upload workflow
2026-06-02 14:49:10 +02:00
Andy ButlandandGitHub 232077e820 EF Core: Retry transient SQLite lock errors during long-running operations (closes #22939) (#22969)
* Retry transient SQLite lock errors during long-running operations.

* Addressed code review comments.
2026-06-02 13:59:37 +02:00
Jacob Overgaard 4e815d7e9d Merge remote-tracking branch 'origin/v17/dev' 2026-06-02 12:46:33 +02:00
Jacob Overgaard 943d1eeccd Merge branch 'release/17.5.0' into v17/dev 2026-06-02 12:44:29 +02:00
Jacob Overgaard b3666dad8b build(deps): bumps @umbraco-ui/uui to 1.18.0 2026-06-02 12:43:21 +02:00
Nhu DinhandGitHub 318843793f E2E: QA Updated acceptance tests for removing the Element Picker from elements to reflect the recent changes (#23037)
* Added comments for the out-of-date tests

* Fixed element with element picker tests due to response changes
2026-06-02 10:20:40 +00:00
Andy Butland c10e23fd92 Merge branch 'v17/dev' 2026-06-01 14:41:53 +02:00
Sven GeusensandAndy Butland 0adb5d21f5 Developer Experience: Improve cohost editor polyfill to work with dotnet watch (closes #22773) (#22999)
* Improve cohost polyfill

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Move <target/> part of the polyfill to targets file.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-06-01 14:40:54 +02:00
Sven GeusensandAndy Butland 28a403361e Developer Experience: Improve cohost editor polyfill to work with dotnet watch (closes #22773) (#22999)
* Improve cohost polyfill

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Move <target/> part of the polyfill to targets file.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-06-01 14:38:35 +02:00
38d73b3a41 Developer Experience: Improve cohost editor polyfill to work with dotnet watch (closes #22773) (#22999)
* Improve cohost polyfill

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Move <target/> part of the polyfill to targets file.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-06-01 12:34:24 +00:00
6143b10643 E2E: QA Added acceptance tests for backoffice element search (#22884)
* Added tests

* Cleaned up

* Updated command

* Fixes based on comments

* Split tests

* Updated helpers

* Fixed constant helper after merge

* Use correct helper

* Added constant for element search

* Added ui helper for element backoffice search

* Added tests for element backoffice search

* Updated tests for finding element by name

* Apply suggestion from @andr317c

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>

* Cleaned up

* Reverted npm command

* Fixed npm command

---------

Co-authored-by: Andreas Zerbst <andr317c@live.dk>
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-06-01 11:07:22 +00:00
577652f707 Backoffice: Strip inherited class comments from TypeDoc API docs (#23004)
* Backoffice: Strip inherited class comments from TypeDoc API docs

TypeDoc copies the nearest documented ancestor's class comment onto every
undocumented subclass, which meant every UmbLitElement descendant on
apidocs.umbraco.com showed "The base class for all Umbraco LitElement
elements." as its own description. This plugin clears class-level
comments whose sourcePath doesn't match the reflection's own file, so
classes with no JSDoc render blank instead of borrowing the base's text.
Inherited member comments (methods, properties) are left alone.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Backoffice: Address review comments on TypeDoc strip-inherited plugin

Drop the misleading "strip trailing line/column" sentence — nothing actually
strips, and a future TypeDoc release that appends positions to sourcePath
would now self-document its breakage instead of being hidden by a comment.

Document the sources[0]-only limitation around declaration merging in the
docblock so the constraint is visible to future maintainers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:59:42 +02:00
Andy ButlandandGitHub 446a3795b7 Elements: Clear user and user group start node references when deleting an element container (closes #23010) (#23011)
* Clear user and user group start nodes when deleting an element container.

* Assert user start node references cleared after container delete

Mirrors the post-delete assertion already present in the user group
sibling test so both tests confirm the reference was cleaned up, not
just that no FK exception was thrown.

* Guard against null entity in PersistDeletedItem override

Mirrors the ArgumentNullException guard in the base
EntityContainerRepository.PersistDeletedItem so a null argument throws
the same exception type.
2026-06-01 10:36:11 +02:00
Niels Lyngsø 5c0cb154f5 cherry picked #23027 2026-06-01 10:04:01 +02:00
Niels LyngsøandGitHub 0d73243b7c Property Editors: Add value summary extensions for collection views (#23027)
Squashed commit of the following:

commit 146b41889b
Author: Mads Rasmussen <madsr@hey.com>
Date:   Wed May 27 13:47:48 2026 +0200

    Delete package-lock.json

commit dd68594995
Author: Mads Rasmussen <madsr@hey.com>
Date:   Wed May 27 13:43:24 2026 +0200

    Simplify content-picker resolved item shape

commit 2bbbd40d9a
Author: Mads Rasmussen <madsr@hey.com>
Date:   Wed May 27 13:21:41 2026 +0200

    content picker value summary add tests & observable support

commit 6a8ee67f54
Author: engjlr <enl@umbraco.dk>
Date:   Wed May 27 12:45:58 2026 +0200

    Inline markdown editor value-type constant

commit 40bd631be5
Author: engjlr <enl@umbraco.dk>
Date:   Wed May 27 11:01:47 2026 +0200

    Remove unused import

commit d066ac4ce0
Author: engjlr <enl@umbraco.dk>
Date:   Wed May 27 10:40:10 2026 +0200

    Enable table text clipping; remove value-summary styles

commit 38a8c77c7b
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 17:00:00 2026 +0200

    Add user-picker value-summary tests and mock

commit 45bcf34186
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 16:44:49 2026 +0200

    Add tests for member-group value resolver

commit a9aad9cff0
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 16:20:37 2026 +0200

    Add member picker value-summary resolver tests

commit e39f3c15ba
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 15:00:36 2026 +0200

    Add media picker value summary resolver tests

commit 9694ac2870
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 14:58:54 2026 +0200

    Update value-summary.resolver.test.ts

commit 641d5f2817
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 14:37:23 2026 +0200

    add tests for the document picker value summary resolver

commit ac8fb96339
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 14:15:39 2026 +0200

    Use check icon for non-empty value summaries

    Replace the document icon with a check icon in value-summary components to indicate non-empty content. Updated the value-summary element in code-editor, markdown-editor, and tiptap-rte to return <uui-icon name='icon-check'> when a value is present, standardizing the visual cue across these editors.

commit 89499c6862
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 13:41:02 2026 +0200

    align member picker

commit 358c8a8629
Author: Mads Rasmussen <madsr@hey.com>
Date:   Tue May 26 13:38:56 2026 +0200

    combine resolver and element into one file to only lazy load one file

commit b759a348c0
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 26 10:30:13 2026 +0200

    Add value-summary manifests to packages

commit 1c692a471b
Merge: d34361b78c fc261d1ce4
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 26 10:29:31 2026 +0200

    Merge remote-tracking branch 'origin/main' into v17/feature/value-summary-property-editors

commit d34361b78c
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 26 10:09:08 2026 +0200

    Update imports

commit 34847e952e
Merge: c194023069 09af8c044b
Author: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Date:   Wed May 20 10:40:23 2026 +0200

    Merge branch 'main' into v17/feature/value-summary-property-editors

commit c194023069
Author: engjlr <enl@umbraco.dk>
Date:   Wed May 20 10:38:04 2026 +0200

    Centralize value summary truncation styles in umb-value-summary-extension

commit 3788be8266
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 19 17:16:51 2026 +0200

    Use item models for resolvers instead of raw string IDs

commit d48fe020f3
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 19 15:32:29 2026 +0200

    Update the visual of tags and block list

commit faf840b67f
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 19 15:22:36 2026 +0200

    Render all the values in the checkbox list

commit 4818c6aef4
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 19 14:36:30 2026 +0200

    Rename value summary element tags and classes to include property-editor

commit 97e4d3474b
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 19 12:36:28 2026 +0200

    Remove undefined from UmbValueTypeMap declarations

commit de4683f6da
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 19 11:44:16 2026 +0200

    Add value summary to element picker

commit d38af1da0c
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 18 16:54:54 2026 +0200

    Guard against raw string value in member group picker value summary

commit f74b1a742a
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 18 14:57:32 2026 +0200

    Export value type constants from package indexes

commit e0067845bf
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 18 12:48:29 2026 +0200

    Fix imports

commit 320dd8fe6f
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 18 11:59:20 2026 +0200

    Use relative repository imports in pickers

commit 9a16b774db
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 18 11:41:10 2026 +0200

    Use DOM parsing for RTE value summary

commit 320bae917c
Merge: 728aedbe0b 18e27151b0
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 18 11:35:12 2026 +0200

    Merge branch 'v17/feature/value-summary-property-editors' of https://github.com/umbraco/Umbraco-CMS into v17/feature/value-summary-property-editors

commit 728aedbe0b
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 18 11:35:09 2026 +0200

    Truncate the fallback element

commit 18e27151b0
Merge: d3c62629d3 4b82828a23
Author: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Date:   Mon May 18 11:25:04 2026 +0200

    Merge branch 'main' into v17/feature/value-summary-property-editors

commit d3c62629d3
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 18 11:09:21 2026 +0200

    Add checkbox-list value summary; truncate labels

commit c593ed2cff
Author: engjlr <enl@umbraco.dk>
Date:   Fri May 15 13:11:16 2026 +0200

    Add valueSummary components for editors

commit 87043d6d2a
Author: engjlr <enl@umbraco.dk>
Date:   Fri May 15 09:17:16 2026 +0200

    Add value summaries for user and member-group pickers

commit 9f1838c581
Author: engjlr <enl@umbraco.dk>
Date:   Wed May 13 12:16:36 2026 +0200

    Add value summaries for content/member/document picker

commit dc9ad61225
Author: engjlr <enl@umbraco.dk>
Date:   Wed May 13 10:37:20 2026 +0200

    Add value summaries for media picker and cropper

commit c97928ebf0
Author: engjlr <enl@umbraco.dk>
Date:   Tue May 12 11:44:41 2026 +0200

    Add value-summary support for several editors

commit ff2ae07a02
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 11 15:59:10 2026 +0200

    Add value summary for multiple text string and tags

commit f7b3da2b7e
Author: engjlr <enl@umbraco.dk>
Date:   Mon May 11 15:14:48 2026 +0200

    Add value summary for Toggle and date/time editors
2026-06-01 10:00:37 +02:00
Andy ButlandandGitHub 3f0e0747fa Management API: Declare multipart/form-data on the Create Temporary File endpoint (closes #23017) (#23025)
Add explicit Consumes to management API endpoint that accepts IFormFile.
2026-06-01 09:32:48 +02:00
Andy Butland 84ad9a1443 Merge branch 'v17/dev' 2026-06-01 08:33:13 +02:00
4a621a13bc Performance: Parallelize independent boot API requests (server status/config + public extensions) (#23020)
* perf(core): parallelize independent boot API requests

UmbServerConnection.connect() awaited server status and configuration
sequentially even though they are independent reads; run them with
Promise.allSettled so both errors surface (the app cannot function
without either) while saving a round-trip.

During app startup, public (login) extension registration was awaited
before the auth flow; kick it off in parallel and await it only before
routing, where the login screen actually needs it.

Each serialized call costs a full management-API round-trip, which is
negligible locally but ~150 ms each on high-latency (e.g. Cloud) hosts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(core): only mark connection connected once both calls succeed

Move isConnected.setValue(true) out of #setStatus() into connect() after
the allSettled check, so the observable never reflects a partially
established connection when configuration fails but status succeeded.

Addresses review feedback on the parallelized connect().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 08:20:34 +02:00
Nhu DinhandGitHub 346a22aeca E2E: QA Added acceptance tests for audit log in element (#22972)
* Added constant variables for element audit trail message

* Added ui helper for history item of element

* Updated tests for audit lofg for element
2026-05-29 15:52:05 +07:00
5cd0f2278c Login: Removes @hey-api/openapi-ts from the login project (#22757)
* feat: removes @hey-api/openapi-ts from the login project

this is an ongoing project to be able to finally  merge 'login' into 'client'

* docs(login): update CLAUDE.md to reflect removal of @hey-api/openapi-ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-28 16:57:06 +01:00
bc2048573c Link Picker: Render picked content/media as non-interactive when their workspace URL can't be resolved (closes #22955) (#22964)
* Entity refs render readonly when their workspace URL can't be resolved.
Also fixes name on remove dialog.

* Apply read-only on the picked content ref only in the non-routable link picker

* Address PR feedback: simplify document item resolver guard in the link picker, document the implicit uui-card-media disabled dependency in input-media, and cover the disabled card state with a test.

* Drop out of date comments.

* Simplify updates.

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-05-28 13:23:48 +00:00
Andy ButlandandGitHub 424209ac06 References: Fix missing node name when content referenced by media or member (closes #22990) (#22965)
Fix missing node name when content referenced by media or member.
2026-05-28 13:34:25 +01:00
Andy Butland 5cf577bf57 Fix broken tiptap reference for storybook build. 2026-05-28 13:32:09 +02:00
ed4b207fe7 Backoffice: Render $index in block detail overlay label (closes #21154) (#22959)
* Render $index in block detail overlay label.

* Cache $index, resolve append sentinel, and cover with unit tests.

* refactor(block): use pipeline for index deduplication and clean up stale observer

* Rename function to remove the unnecessary umb prefix.

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-05-28 11:15:21 +00:00
Andy ButlandandGitHub 40e027d0ea Content Type Editor: Fix empty Design tab when opened in a modal workspace (closes #22855) (#22954)
* Fix empty content type Design tab when opened in a modal workspace.

* Addressed code review comments.

* Fixed failing E2E tests.
2026-05-28 09:39:11 +00:00
Andy Butland 70258066d4 Merge branch 'v17/dev' 2026-05-28 10:46:31 +02:00
Andy Butland 5cfbfe7cc3 Merge branch 'v17/dev' 2026-05-28 10:44:20 +02:00
Andy ButlandandGitHub a6f6bdf8bc Backoffice: Hide "Edit permissions" button in create modals from users without Settings section access (closes #22981) (#22984)
* Show the edit permissions for document type button only for users with settings access.

* Fix translation for message (the "Permissions" tab is not called "Structure").

* Addressed code review feedback.
2026-05-28 09:23:26 +01:00
Andy Butland 4b9c0eb667 Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-05-28 09:56:39 +02:00
Laura Neto f3471e961f Bump version to 18.0.0-rc2 2026-05-28 09:56:34 +02:00
2581e3fdbc Code Quality: Fix CS0618 obsolete API warnings in Umbraco.Examine.Lucene project (#22978)
* Suppress CS0618 obsolete API warnings in Umbraco.Examine.Lucene

Each obsolete API in this project cannot be migrated to its
non-obsolete replacement without either a breaking public API
change or a change in runtime behaviour:

- LuceneIndex.CommitCount: obsolete with no replacement; retained
  in diagnostics metadata to preserve existing output
- IHostingEnvironment.MapPathContentRoot: the IHostEnvironment
  extension replacement resolves a different environment
  abstraction
- FileSystemDirectoryFactory base constructor: the non-obsolete
  overload alters Lucene directory configuration behaviour

Each warning is suppressed locally with an explanatory comment
rather than changed, preserving existing behaviour.

Fixes #15015

* Tightened up comments. Added obsoletion version on unversioned attributes.
Removed warning supressions and fixed constructors.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-28 09:54:55 +02:00
Jacob Overgaard 4f5985c4d0 build: fixed timeoutInMinutes which should be on the task-level and not job-level 2026-05-28 09:28:40 +02:00
Jacob Overgaard 7d63afe8d6 Merge branch 'release/18.0' 2026-05-28 08:56:53 +02:00
Jacob OvergaardandClaude Opus 4.7 45686c982e Backoffice: Drop redundant search manifest import from Storybook preview
`core/manifests.ts` already imports and spreads `core/search/manifests.ts`
into its aggregate (line 23 + 58), so importing `searchManifests`
separately in `.storybook/preview.js` and spreading it next to
`coreManifests` registered the same manifests twice. Remove the redundant
import and spread.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:52:38 +02:00
Jacob OvergaardandClaude Opus 4.7 d97d508a48 Backoffice: Repoint Storybook preview imports at umbraco-package.ts
PR #22957 deleted every package's `manifests.ts` and consolidated the
exports into `umbraco-package.ts`, but `.storybook/preview.js` still
imported from the old paths. The result was a Vite resolve error during
`npm run build-storybook` (first failure: "Could not resolve
../src/packages/block/manifests from .storybook/preview.js").

37 import paths swapped from `…/<pkg>/manifests` to
`…/<pkg>/umbraco-package`. The two packages that still expose their
manifests via a standalone `manifests.ts` — `core` and `core/search` —
are left untouched.

Verified by `npm run build-storybook` — succeeds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:49:58 +02:00
Jacob OvergaardandClaude Opus 4.7 db590b0724 Tiptap: Fix dead manifests.js import in the input-tiptap story
PR #22995 added `input-tiptap.stories.ts` with an import from
`'../../manifests.js'`, but PR #22957 (already on release/17.5.0) had
deleted that file and moved the `manifests` array into
`umbraco-package.ts`. The merge into release/17.5.0 didn't catch the dead
import, so Storybook 404s on the story load.

Point the import at the new home — `manifests` is still exported by name,
so this is a one-line path fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:49:07 +02:00
Jacob OvergaardandClaude Opus 4.7 8e6a791de0 Backoffice: Drop redundant search manifest import from Storybook preview
`core/manifests.ts` already imports and spreads `core/search/manifests.ts`
into its aggregate (line 23 + 58), so importing `searchManifests`
separately in `.storybook/preview.js` and spreading it next to
`coreManifests` registered the same manifests twice. Remove the redundant
import and spread.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:47:38 +02:00
Jacob OvergaardandClaude Opus 4.7 5ffea3152b Backoffice: Repoint Storybook preview imports at umbraco-package.ts
PR #22957 deleted every package's `manifests.ts` and consolidated the
exports into `umbraco-package.ts`, but `.storybook/preview.js` still
imported from the old paths. The result was a Vite resolve error during
`npm run build-storybook` (first failure: "Could not resolve
../src/packages/block/manifests from .storybook/preview.js").

37 import paths swapped from `…/<pkg>/manifests` to
`…/<pkg>/umbraco-package`. The two packages that still expose their
manifests via a standalone `manifests.ts` — `core` and `core/search` —
are left untouched.

Verified by `npm run build-storybook` — succeeds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:43:38 +02:00
Jacob OvergaardandClaude Opus 4.7 2043ff1dbd Tiptap: Fix dead manifests.js import in the input-tiptap story
PR #22995 added `input-tiptap.stories.ts` with an import from
`'../../manifests.js'`, but PR #22957 (already on release/17.5.0) had
deleted that file and moved the `manifests` array into
`umbraco-package.ts`. The merge into release/17.5.0 didn't catch the dead
import, so Storybook 404s on the story load.

Point the import at the new home — `manifests` is still exported by name,
so this is a one-line path fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:40:17 +02:00
Andy ButlandandJacob Overgaard 6a4b792ff1 Fix StoryBook build failure following updates in #22957. 2026-05-28 08:34:03 +02:00
Jacob Overgaard 85e0169100 Merge branch 'release/18.0' 2026-05-28 08:28:32 +02:00
Jacob OvergaardandClaude Opus 4.7 0b5438935d Tiptap: Load enabled extensions in parallel and inline manifest APIs (#22995)
* Tiptap: Load enabled extensions in parallel and inline manifest APIs

Replace the for…of/await loop in umb-input-tiptap's #loadExtensions with
Promise.all over .map, so all enabled Tiptap extension APIs are fetched
in parallel. Configured-extension order in _extensions is preserved.

Inline the first-party Tiptap manifest API references: every
`api: () => import('./X.tiptap-api.js')` and the equivalent toolbar /
statusbar / kind references now use a static top-of-file import and
`api: ClassName`. The dynamic `await import('rich-text-essentials.tiptap-api.js')`
fallback in input-tiptap.element.ts is inlined for the same reason.

External (plugin-supplied) Tiptap extensions and the lazy modal/toolbar
UI element imports are unchanged.

Why: on Umbraco Cloud, opening a document workspace with a rich text
editor takes ~16 s uncached, of which ~14.6 s is a single serial
waterfall — 31 extension APIs fetched one after the other from a
for…of await loop, ~170 ms RTT stacked. Replacing the loop with
Promise.all collapses that to roughly one round-trip; eagerly bundling
the first-party manifests removes the dynamic chunk explosion that made
the waterfall so long in the first place. The toolbar APIs (~20 of them)
already load in a sub-100 ms parallel burst against the same server,
confirming HTTP/2 multiplexing handles bulk parallel requests fine.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Tiptap: Inline element references for toolbar/statusbar/modal/clipboard manifests

Extends the manifest-inlining pass to the remaining `element: () => import(...)`
and runtime API loader sites in the Tiptap package — toolbar/menu/action-button
kinds, the table & character-map & anchor modals, the colour-picker button, the
property-editor configuration UIs, both clipboard translators, the style-menu
kind, and the default toolbar API fallback in tiptap-toolbar.element.ts.

Result on the same Cloud test site (uncached, 17.5-rc):
  Tiptap chunk count: 71 → 4
  Total tiptap bytes: ~3.2 MB → ~3.1 MB (essentially unchanged)
  Phase 5 of the load — the serial extension chain — collapses to a single
  consolidated chunk fetch.

`input-tiptap.element.ts` and `property-editor-ui-tiptap.element.ts` are
intentionally not inlined into anything else: `<umb-input-tiptap>` is a public
element usable standalone (custom dashboards, workspace views), and the
property-editor shell loads via the property-editor UI loader. They remain
exported as their own modules.

CLAUDE.md updated to document the new convention for first-party Tiptap
extensions (direct class refs) and the carve-out for external plugin
extensions that may keep `() => import(...)` to ship their API code in a
separate chunk.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Tiptap: Move extension APIs and elements into a shared lazy boundary chunk

The previous PR collapsed ~70 Tiptap chunks into 3 by inlining first-party API
and element references directly into manifest files. That win came with a real
downside flagged in code review (lke / mra): the API/element implementation
bytes ended up in the manifest registration bundle, so every workspace —
including ones without an RTE — paid ~700 KB of Tiptap code on boot.

This commit keeps the chunk-coalescing win but restores the lazy boundary by
routing every first-party manifest's `api` / `element` reference through a
single shared bundle file `extensions/extension-apis.bundle.ts`. Each manifest
holds a dynamic-import thunk pointing at that one bundle, so:

- Rollup still emits a single chunk for all Tiptap extension code (no chunk
  explosion).
- The manifest registration bundle stays slim — it carries only metadata
  (alias / label / icon / group / kind / forExtensions) plus the thunks.
- The bundle is only fetched the first time `<umb-input-tiptap>` actually
  mounts.

Data-type configuration UIs (`extensions-configuration`,
`toolbar-configuration`, `statusbar-configuration`) read manifest metadata
via `umbExtensionsRegistry.byType(...)` only — they never call
`loadManifestApi` / `loadManifestElement`, so the data-type editor continues
to work without loading any Tiptap implementation code.

Property-editor UI elements (`tiptap-rte`, the three configuration UIs) also
revert to `() => import('./X.element.js')` so each loads on demand from its
own chunk rather than being inlined into the manifest bundle.

`umb-input-tiptap` no longer statically imports the Rich Text Essentials API;
it prepends the alias to the observed list instead, so essentials resolves
through the same lazy bundle as every other extension.

Added a test and stories file that mount `<umb-input-tiptap>` standalone (no
property-editor wrapper) to make the public usage pattern explicit.

Built and verified via `npm run build:for:cms`:
- `dist-cms/packages/tiptap/manifests.js`           48 KB  (eager at boot)
- `dist-cms/packages/tiptap/extension-apis.bundle-*.js` 84 KB  (lazy)
- `dist-cms/packages/tiptap/tiptap-toolbar-element-api-base-*.js` 654 KB
  (lazy dependency of the bundle)
- per-element property-editor UI chunks load on demand when settings open

`npm run check:circular`, `npm run compile`, `npx wtr src/packages/tiptap`
all pass.

Related to #21152, builds on #22995.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Tiptap: Don't mount <umb-input-tiptap> in the standalone test

Mounting the element via fixture() spins up an UmbTiptapRteContext that
consumes UMB_SERVER_CONTEXT. In the unit-test runtime no server context
provider exists, so the context request stays pending. When @open-wc's
fixture tears down at end-of-file the request rejects with
"host disconnected" — surfaced as an unhandled promise rejection that
web-test-runner counts as a fatal runner error, exiting 1 even though every
individual test passed. The rejection happened to be in flight while a
block-grid clipboard test was active in CI, which is why the failure surfaced
there rather than in the tiptap test file itself.

Drop the manifest-registration assertion too — pulling the package-level
`manifests.ts` aggregator triggers a transitive 404 on the
`@umbraco-cms/backoffice/tiptap` importmap entry in the wtr environment.

The class-export + custom-element-registration checks are enough to prove
standalone exportability. The Storybook stories still cover the visual
end-to-end load path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:28:18 +02:00
Jacob Overgaard f1bc1db6ce Merge branch 'v17/dev' of https://github.com/umbraco/Umbraco-CMS into v17/dev 2026-05-28 08:27:15 +02:00
Jacob Overgaard c4d5b89fc5 Merge remote-tracking branch 'origin/release/17.5.0' into v17/dev 2026-05-28 08:27:04 +02:00
7597a8ad40 Sort Dialog: Show current language node names (closes #22872) (#22948)
* Display variant node name on sort children dialog.

* Preserve user sort order when patching variant names on culture change

Patch names in-place on the existing _tableItems rather than rebuilding
from _children, so a user's drag-sorted or column-ordered arrangement is
not silently reverted if the app culture changes while the modal is open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Refactor to reduce cyclomatic complexity of #resolveName method.

* Resolve sort dialog variant names and icons via item data resolvers

Replace the inlined variant-name logic in the content sort dialog with the
shared UmbItemDataResolver abstraction, and add UmbMediaItemDataResolver so
media items resolve their active-culture name and icon the same way documents
do. Each content sort entity action now supplies its resolver through manifest
meta, flowing into the modal via a new content-specific modal data type and a
base-action _getModalData() hook. This also removes the previously hard-coded
document icon in the dialog.

* Disable load more when page of items is being retrieved.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-05-28 05:50:16 +00:00
d28507e2e5 Migrations: Convert all sibling RTE blocks (closes #22979) (#22980)
* Fix migration of embedded block data when blocks are direct siblings in the 13 RTE source code.

* Apply suggestions from code review to update comments.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Address review: keep RteBlockHelper in original namespace; tidy docs and comment

- Move RteBlockHelper back to Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_0_0.LocalLinks
  to avoid a binary breaking change within the obsolete window (scheduled removal in v18).
  Kept as its own file rather than reverting it into LocalLinkRteProcessor.cs.
- Add a <remarks> note on ConvertBlockUdisToKeys explaining that blocks with malformed UDIs
  are dropped rather than preserved.
- Replace the opaque "fix recursive hiccup" comment in LocalLinkRteProcessor with one that
  describes what the line actually does.
- Move RteBlockHelperTests back to mirror the production namespace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 07:45:01 +02:00
7b75324172 Migrations: Convert all sibling RTE blocks (closes #22979) (#22980)
* Fix migration of embedded block data when blocks are direct siblings in the 13 RTE source code.

* Apply suggestions from code review to update comments.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Address review: keep RteBlockHelper in original namespace; tidy docs and comment

- Move RteBlockHelper back to Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_0_0.LocalLinks
  to avoid a binary breaking change within the obsolete window (scheduled removal in v18).
  Kept as its own file rather than reverting it into LocalLinkRteProcessor.cs.
- Add a <remarks> note on ConvertBlockUdisToKeys explaining that blocks with malformed UDIs
  are dropped rather than preserved.
- Replace the opaque "fix recursive hiccup" comment in LocalLinkRteProcessor with one that
  describes what the line actually does.
- Move RteBlockHelperTests back to mirror the production namespace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 07:38:56 +02:00
172a3be5ac Repositories: Batch WHERE IN queries to avoid SQL Server 2100-parameter limit (#22987)
* Batch WHERE IN queries to avoid SQL Server 2100-parameter limit and add memory files.

* Drop past-incident references from SQL parameter-limit docs

The memory files should describe the current rule and safe patterns;
specific historical bugs belong in commit history, not CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update comments from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Addressed memory file feedback.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-28 10:44:15 +09:00
ca28195b7c Tiptap: Load enabled extensions in parallel and inline manifest APIs (#22995)
* Tiptap: Load enabled extensions in parallel and inline manifest APIs

Replace the for…of/await loop in umb-input-tiptap's #loadExtensions with
Promise.all over .map, so all enabled Tiptap extension APIs are fetched
in parallel. Configured-extension order in _extensions is preserved.

Inline the first-party Tiptap manifest API references: every
`api: () => import('./X.tiptap-api.js')` and the equivalent toolbar /
statusbar / kind references now use a static top-of-file import and
`api: ClassName`. The dynamic `await import('rich-text-essentials.tiptap-api.js')`
fallback in input-tiptap.element.ts is inlined for the same reason.

External (plugin-supplied) Tiptap extensions and the lazy modal/toolbar
UI element imports are unchanged.

Why: on Umbraco Cloud, opening a document workspace with a rich text
editor takes ~16 s uncached, of which ~14.6 s is a single serial
waterfall — 31 extension APIs fetched one after the other from a
for…of await loop, ~170 ms RTT stacked. Replacing the loop with
Promise.all collapses that to roughly one round-trip; eagerly bundling
the first-party manifests removes the dynamic chunk explosion that made
the waterfall so long in the first place. The toolbar APIs (~20 of them)
already load in a sub-100 ms parallel burst against the same server,
confirming HTTP/2 multiplexing handles bulk parallel requests fine.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Tiptap: Inline element references for toolbar/statusbar/modal/clipboard manifests

Extends the manifest-inlining pass to the remaining `element: () => import(...)`
and runtime API loader sites in the Tiptap package — toolbar/menu/action-button
kinds, the table & character-map & anchor modals, the colour-picker button, the
property-editor configuration UIs, both clipboard translators, the style-menu
kind, and the default toolbar API fallback in tiptap-toolbar.element.ts.

Result on the same Cloud test site (uncached, 17.5-rc):
  Tiptap chunk count: 71 → 4
  Total tiptap bytes: ~3.2 MB → ~3.1 MB (essentially unchanged)
  Phase 5 of the load — the serial extension chain — collapses to a single
  consolidated chunk fetch.

`input-tiptap.element.ts` and `property-editor-ui-tiptap.element.ts` are
intentionally not inlined into anything else: `<umb-input-tiptap>` is a public
element usable standalone (custom dashboards, workspace views), and the
property-editor shell loads via the property-editor UI loader. They remain
exported as their own modules.

CLAUDE.md updated to document the new convention for first-party Tiptap
extensions (direct class refs) and the carve-out for external plugin
extensions that may keep `() => import(...)` to ship their API code in a
separate chunk.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Tiptap: Move extension APIs and elements into a shared lazy boundary chunk

The previous PR collapsed ~70 Tiptap chunks into 3 by inlining first-party API
and element references directly into manifest files. That win came with a real
downside flagged in code review (lke / mra): the API/element implementation
bytes ended up in the manifest registration bundle, so every workspace —
including ones without an RTE — paid ~700 KB of Tiptap code on boot.

This commit keeps the chunk-coalescing win but restores the lazy boundary by
routing every first-party manifest's `api` / `element` reference through a
single shared bundle file `extensions/extension-apis.bundle.ts`. Each manifest
holds a dynamic-import thunk pointing at that one bundle, so:

- Rollup still emits a single chunk for all Tiptap extension code (no chunk
  explosion).
- The manifest registration bundle stays slim — it carries only metadata
  (alias / label / icon / group / kind / forExtensions) plus the thunks.
- The bundle is only fetched the first time `<umb-input-tiptap>` actually
  mounts.

Data-type configuration UIs (`extensions-configuration`,
`toolbar-configuration`, `statusbar-configuration`) read manifest metadata
via `umbExtensionsRegistry.byType(...)` only — they never call
`loadManifestApi` / `loadManifestElement`, so the data-type editor continues
to work without loading any Tiptap implementation code.

Property-editor UI elements (`tiptap-rte`, the three configuration UIs) also
revert to `() => import('./X.element.js')` so each loads on demand from its
own chunk rather than being inlined into the manifest bundle.

`umb-input-tiptap` no longer statically imports the Rich Text Essentials API;
it prepends the alias to the observed list instead, so essentials resolves
through the same lazy bundle as every other extension.

Added a test and stories file that mount `<umb-input-tiptap>` standalone (no
property-editor wrapper) to make the public usage pattern explicit.

Built and verified via `npm run build:for:cms`:
- `dist-cms/packages/tiptap/manifests.js`           48 KB  (eager at boot)
- `dist-cms/packages/tiptap/extension-apis.bundle-*.js` 84 KB  (lazy)
- `dist-cms/packages/tiptap/tiptap-toolbar-element-api-base-*.js` 654 KB
  (lazy dependency of the bundle)
- per-element property-editor UI chunks load on demand when settings open

`npm run check:circular`, `npm run compile`, `npx wtr src/packages/tiptap`
all pass.

Related to #21152, builds on #22995.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Tiptap: Don't mount <umb-input-tiptap> in the standalone test

Mounting the element via fixture() spins up an UmbTiptapRteContext that
consumes UMB_SERVER_CONTEXT. In the unit-test runtime no server context
provider exists, so the context request stays pending. When @open-wc's
fixture tears down at end-of-file the request rejects with
"host disconnected" — surfaced as an unhandled promise rejection that
web-test-runner counts as a fatal runner error, exiting 1 even though every
individual test passed. The rejection happened to be in flight while a
block-grid clipboard test was active in CI, which is why the failure surfaced
there rather than in the tiptap test file itself.

Drop the manifest-registration assertion too — pulling the package-level
`manifests.ts` aggregator triggers a transitive 404 on the
`@umbraco-cms/backoffice/tiptap` importmap entry in the wtr environment.

The class-export + custom-element-registration checks are enough to prove
standalone exportability. The Storybook stories still cover the visual
end-to-end load path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 14:32:20 +00:00
Jacob Overgaard 4520bb6e91 Merge branch 'release/18.0' 2026-05-27 14:33:46 +02:00
Mads RasmussenandJacob Overgaard 18c559a3bb Backoffice: Embed implementations directly in core manifests to reduce startup network requests (#22944)
* Use direct imports in core manifests

* Extract theme aliases into constants file

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-05-27 14:32:57 +02:00
Mads RasmussenandJacob Overgaard 893bb61d0d Backoffice: Embed package root manifests into umbraco-package.ts to reduce startup requests (#22957)
* Consolidate block package into index export

* keep umbraco-package.ts and embed manifests instead

* Inline package manifests into umbraco-package

* update docs
2026-05-27 14:31:36 +02:00
Mads RasmussenandJacob Overgaard 5b800deb3c Backoffice: Swap relative imports to @umbraco-cms/backoffice module imports in core packages (#22942)
Use @umbraco-cms/backoffice imports

Replace numerous relative/internal import paths with centralized '@umbraco-cms/backoffice' package entry points across core modules.This consolidates exports, simplifies import paths.
2026-05-27 14:31:29 +02:00
Jacob Overgaard 5a5902e1d4 Merge remote-tracking branch 'origin/v17/dev' 2026-05-27 14:28:44 +02:00
Jacob Overgaard 4c1fde9e0c Merge branch 'release/17.5.0' into v17/dev 2026-05-27 14:28:03 +02:00
Mads RasmussenandJacob Overgaard f0013330e6 Backoffice: Embed package root manifests into umbraco-package.ts to reduce startup requests (#22957)
* Consolidate block package into index export

* keep umbraco-package.ts and embed manifests instead

* Inline package manifests into umbraco-package

* update docs
2026-05-27 14:26:56 +02:00
Mads RasmussenandJacob Overgaard bd2c985187 Backoffice: Embed implementations directly in core manifests to reduce startup network requests (#22944)
* Use direct imports in core manifests

* Extract theme aliases into constants file

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-05-27 14:26:34 +02:00
Mads RasmussenandJacob Overgaard 9711a5d012 Backoffice: Swap relative imports to @umbraco-cms/backoffice module imports in core packages (#22942)
Use @umbraco-cms/backoffice imports

Replace numerous relative/internal import paths with centralized '@umbraco-cms/backoffice' package entry points across core modules.This consolidates exports, simplifies import paths.
2026-05-27 14:24:57 +02:00
Engiber Lozadaandleekelleher 9cf3a7e296 Content Editor: Fix workspace footer breadcrumb overflow hiding (closes #20132) (#22323)
* Allow the breadcrumbs to collapse in the workspace view

* Remove redundant styles

(cherry picked from commit 52cccafa86)
2026-05-27 11:56:06 +01:00
Engiber LozadaandGitHub 52cccafa86 Content Editor: Fix workspace footer breadcrumb overflow hiding (closes #20132) (#22323)
* Allow the breadcrumbs to collapse in the workspace view

* Remove redundant styles
2026-05-27 10:52:49 +00:00
Jacob Overgaard c2416429b7 Merge remote-tracking branch 'origin/v17/dev' 2026-05-27 09:45:15 +02:00
Andreas Zerbst 2fa7067803 Fixed required value 2026-05-27 09:27:13 +02:00
Andy ButlandandGitHub 808cba2747 Members: Default Approved to true when creating a member (closes #22991) (#22993)
Default new members created via the backoffice to approved.
2026-05-27 06:59:24 +00:00
mole b0a825e6c0 Fix test filters 2026-05-26 12:31:44 +02:00
Mads Rasmussen da0117f240 Merge branch 'v17/dev' of https://github.com/umbraco/Umbraco-CMS into v17/dev 2026-05-26 09:50:48 +02:00
mole fc261d1ce4 Fix intergration tests 2026-05-26 09:40:12 +02:00
Jacob Overgaard 31944675c0 Merge remote-tracking branch 'origin/v17/dev' 2026-05-26 08:33:28 +02:00
Jacob OvergaardandGitHub 61d3e4c53d Backoffice: Add Cache-Control headers to cache-busted backoffice assets (AB#68478) (#22951)
* Backoffice: Add Cache-Control headers to cache-busted backoffice assets (AB#68478)

Adds a UseUmbracoBackOfficeCacheHeaders middleware that sets
Cache-Control: public, max-age=31536000, immutable on responses served
from the cache-busted backoffice path (/umbraco/backoffice/<hash>/*).
The hash in the URL is derived from the Umbraco version, so the URL
itself invalidates on every release - making 'immutable' safe regardless
of whether individual filenames contain a content hash.

In debug mode the cache-bust hash changes per request, so the header is
set to 'no-cache' to avoid filling the browser disk cache with single-use
entries.

Design is non-destructive to consumer customisation, addressing the
review feedback on the v14 attempt (#14475):

- Does not touch StaticFileOptions; consumer
  services.Configure<StaticFileOptions>(...) and OnPrepareResponse
  callbacks continue to work unchanged.
- Sets the header via Response.OnStarting with a ContainsKey guard, so
  any synchronous Cache-Control set upstream wins; consumer OnStarting
  callbacks registered later fire first (LIFO) and also win.
- Skips non-2xx responses to avoid long-lived caching of error responses.

Related: GH #21152, PR #22896.

* Backoffice: Correct rationale for no-cache in debug mode

Reword the XML doc on UseUmbracoBackOfficeCacheHeaders to reflect that
IBackOfficePathGenerator is a singleton, so the cache-bust hash is
computed once at startup even in debug mode (per Copilot review on
#22951). The reason for no-cache is not "hash changes per request" but
that built assets may change in place during dev iteration; no-cache
allows fast 304 revalidation while no-store would force full
re-downloads.

No functional change.

* Backoffice: Add unit tests for UseUmbracoBackOfficeCacheHeaders

Covers six scenarios via a minimal in-process pipeline composed with
Microsoft.AspNetCore.TestHost:

- Production: 200 under hash prefix gets immutable header
- Debug: 200 under hash prefix gets no-cache
- Non-2xx under prefix: header not set (status gate)
- Path outside prefix: header not set (path gate)
- Consumer synchronous override: ContainsKey guard skips, consumer wins
- Consumer OnStarting override: LIFO ordering lets consumer win

Adds Microsoft.AspNetCore.TestHost to Umbraco.Tests.UnitTests (standard
Microsoft package, version pinned in tests/Directory.Packages.props).

* Backoffice: Extract cache-headers logic into IMiddleware class

Matches the existing Umbraco middleware convention (BootFailedMiddleware,
PreviewAuthenticationMiddleware, UmbracoRequestMiddleware, etc.) per
Kenn's note: prefer UseMiddleware<T>() with a DI-resolved class over
inline builder.Use lambdas.

The new UmbracoBackOfficeCacheHeadersMiddleware:
- Implements IMiddleware; registered as a singleton in AddWebComponents
- Computes prefix and header value once in the constructor (both
  dependencies are singletons themselves, so this is stable)
- Behaviour is unchanged from the inline version

The UseUmbracoBackOfficeCacheHeaders extension method becomes a thin
UseMiddleware<T>() wrapper. Tests updated to register the middleware in
the TestServer DI container so it can be resolved through UseMiddleware.

* Backoffice: Document IMiddleware convention in Web.Common CLAUDE.md

Adds an explicit "Convention" note before the middleware list so future
contributors (and AI assistants) default to the IMiddleware class +
AddSingleton + UseMiddleware<T>() pattern rather than inline
builder.Use(async ...) lambdas. Also lists the new
UmbracoBackOfficeCacheHeadersMiddleware in the folder structure and
middleware reference.

* Backoffice: Tighten middleware convention note with full corroboration

Lists every IMiddleware implementer in the codebase (10/10) and calls
out the two known inline-lambda exceptions (CspNonceExtensions,
WebApplicationExtensions) so the rule reads as the established
convention rather than an absolute, while still steering new work
toward IMiddleware + AddSingleton + UseMiddleware<T>().

* Backoffice: Register cache-headers middleware in AddBackOfficeCore

DI scope validation runs in Development/CI and pre-checks every
singleton's dependency graph can be constructed. The middleware was
registered in AddWebComponents (which runs for every Umbraco bootstrap),
but its IBackOfficePathGenerator dependency is only registered by
AddBackOffice(). The previous CI run on this branch surfaced the
problem in four Delivery-only/Website-only bootstrap tests
(CoreWithDeliveryApi_BootsSuccessfully, DeliveryOnlyScenario_BootsSuccessfully,
etc.) with "Unable to resolve service for type 'IBackOfficePathGenerator'
while attempting to activate 'UmbracoBackOfficeCacheHeadersMiddleware'".

Move the registration alongside IBackOfficePathGenerator in
AddBackOfficeCore (Api.Management), which is the same scope as the
backoffice itself. This also matches the wire-up gate in
UmbracoApplicationBuilder.cs that only calls UseUmbracoBackOfficeCacheHeaders
when IBackOfficeEnabledMarker is registered.

CLAUDE.md updated with the rule ("register the middleware next to its
dependencies' registration") and a pitfall note about DI scope validation.

* Backoffice: Address review feedback from AndyButland (PR #22951)

- Move UseUmbracoBackOfficeCacheHeadersTests from Umbraco.Tests.UnitTests
  to Umbraco.Tests.Integration. It uses HostBuilder + TestServer to
  exercise the real HTTP pipeline, which is integration-shaped rather
  than unit-shaped. Drop Microsoft.AspNetCore.TestHost from UnitTests
  (Mvc.Testing in Integration provides it transitively) and from
  tests/Directory.Packages.props.
- Soften the misleading "no trailing slash" comment in
  UmbracoBackOfficeCacheHeadersMiddleware — we trim anyway, so the
  comment is now framed as defensive normalisation.
- Trim the dense middleware convention note in Web.Common/CLAUDE.md to
  one paragraph (rule + the two known inline-lambda exceptions). Move
  the DI-scope-validation pitfall narrative out of CLAUDE.md and into a
  three-line code comment next to the AddSingleton call in
  AddBackOfficeCore where it actually applies.

* Backoffice: HTTP verb gate, 304 inclusion, namespace + unused using (PR #22951 review)

Three more from AndyButland's review:

1. Verb gate + 304 inclusion in UmbracoBackOfficeCacheHeadersMiddleware.
   Restrict the path-prefix match to GET and HEAD so POST/PUT/DELETE
   responses and OPTIONS (CORS preflight) responses don't get tagged as
   immutable. Include 304 alongside 2xx in the status gate so
   intermediate caches (CDN/proxy) receive the Cache-Control directive on
   revalidation responses too. Extended the test suite with four new
   cases: NotModifiedResponseUnderPrefix_SetsImmutable,
   HeadRequestUnderPrefix_SetsImmutable,
   OptionsRequestUnderPrefix_DoesNotSetHeader,
   PostRequestUnderPrefix_DoesNotSetHeader. All 10 tests pass.
2. Test namespace updated to Umbraco.Cms.Tests.Integration.* to match
   the convention used by ~629 other files in Umbraco.Tests.Integration
   (vs the 2 outliers I copied from).
3. Drop unused 'using Umbraco.Extensions;' from the test file.

* Backoffice: Extract conditional checks to satisfy CodeScene complexity gate

CodeScene flagged InvokeAsync with "Complex Conditional" (advisory rule,
code health impact 9.69) after the verb + 304 additions in the prior
commit. Extract the two checks into IsCacheableAssetRequest and
ShouldSetCacheControl helper methods. No behaviour change; tests still
green (10/10, 149 ms).
2026-05-26 08:31:10 +02:00
Andy Butland 5a28f6e0f1 Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-05-26 06:33:52 +02:00
Zeegaan 6e2ba699ee Merge remote-tracking branch 'origin/v17/dev' 2026-05-26 12:22:28 +09:00
51d70877d1 QA: Stabilise rollback content versioning E2E test (#22975)
* Stabilise rollback E2E test by waiting for document reload before asserting.

* Condense rollback wait comment per code-review feedback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Addressed code review feedback.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 12:21:03 +09:00
Andy ButlandandGitHub 2dcfe68208 Backoffice search: Preserve Lucene score order through content-picker lookups (closes #22862) (#22977)
* Preserve Lucene score order through content-picker lookups.

* Removed unnecessary tests.  Addressed code review comments.
2026-05-26 12:15:21 +09:00
ce06c4ba4d Management API: ensure the order from the search endpoints taking a collection of keys is preserved (#22973)
* ensure the order from the search endpoints taking a collection of keys is preserved

* Align cosmetic changes to ensure later merge up doesn't run into conflicts.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-25 17:32:17 +00:00
Andy Butland c2b6210137 Merge branch 'v17/dev' 2026-05-25 10:21:31 +02:00
Andy Butland a91de6e677 Fix StoryBook build failure following updates in #22957. 2026-05-25 10:20:45 +02:00
Andy Butland f7a45dc9d6 Merge branch 'v17/dev' 2026-05-25 10:13:58 +02:00
faf3824a0a Backoffice: Embed implementations directly in core manifests to reduce startup network requests (#22944)
* Use direct imports in core manifests

* Extract theme aliases into constants file

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-05-25 10:07:24 +02:00
9cd2e6ecd2 Management API: ensure the order from the search endpoints taking a collection of keys is preserved (#22920)
* update order search result for element, member type, dictionary...

* undo dictionary search API

* reorder search value

* Apply OrderByRequestedIds

* add unit tests for search order

* Reverted unnecessarily changed files, minor test clean-up, aligned controllers for XML docs.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-25 07:38:49 +00:00
Andy Butland c64c6cfd92 Merge branch 'v17/dev' 2026-05-25 08:35:28 +02:00
Andy Butland ca30a7604e Merge branch 'release/18.0' 2026-05-25 08:35:09 +02:00
Ronald BarendseandAndy Butland 3d430f7f83 Background Jobs: Refine RecurringBackgroundJobBase API (#22966)
* Add IgnoredDelayChanged event to allow updates during back-off

* Make Period and IgnoredDelay settable on RecurringBackgroundJobBase with auto-raising events

* Address PR review: handle CTS race, restore negative-IgnoredDelay guard, clarify setter remarks

- Swallow ObjectDisposedException in OnIgnoredDelayChanged for the shutdown race where an in-flight handler reads the to-be-disposed CTS via Interlocked.Exchange before Dispose disposes it.
- Restore "skip back-off when IgnoredDelay <= TimeSpan.Zero (and not Timeout.InfiniteTimeSpan)" guard in IgnoreAndWaitAsync to defend against direct IRecurringBackgroundJob implementations / property overrides returning a negative value that would otherwise tight-loop via ComputeNextDelay clamping to zero.
- Add regression test for the negative-IgnoredDelay skip path.
- Mirror the constructor "stored without raising" remark on the Period and IgnoredDelay setter doc comments.

* Dispose newly-installed CTS when shutdown race wins the rotate-and-cancel

* Clarify XML docs.

* Introduce helper for cancellation source rotate and cancel.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-25 08:02:14 +02:00
Andy Butland 58ed9899be Merge branch 'release/17.5.0' into v17/dev 2026-05-25 08:01:04 +02:00
Engiber LozadaandGitHub bc7bd9a32a Body Layout: Replace overflow: auto with uui-scroll-container (#22950)
* replace overflow: auto with uui-scroll-container in layout components

* Remove stale comment
2026-05-25 07:57:22 +02:00
8160ede4b6 Background Jobs: Refine RecurringBackgroundJobBase API (#22966)
* Add IgnoredDelayChanged event to allow updates during back-off

* Make Period and IgnoredDelay settable on RecurringBackgroundJobBase with auto-raising events

* Address PR review: handle CTS race, restore negative-IgnoredDelay guard, clarify setter remarks

- Swallow ObjectDisposedException in OnIgnoredDelayChanged for the shutdown race where an in-flight handler reads the to-be-disposed CTS via Interlocked.Exchange before Dispose disposes it.
- Restore "skip back-off when IgnoredDelay <= TimeSpan.Zero (and not Timeout.InfiniteTimeSpan)" guard in IgnoreAndWaitAsync to defend against direct IRecurringBackgroundJob implementations / property overrides returning a negative value that would otherwise tight-loop via ComputeNextDelay clamping to zero.
- Add regression test for the negative-IgnoredDelay skip path.
- Mirror the constructor "stored without raising" remark on the Period and IgnoredDelay setter doc comments.

* Dispose newly-installed CTS when shutdown race wins the rotate-and-cancel

* Clarify XML docs.

* Introduce helper for cancellation source rotate and cancel.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-25 05:42:41 +00:00
Jacob Overgaard d2e32d6fcb Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-05-23 10:11:21 +02:00
Jacob Overgaard bec333e37b Merge remote-tracking branch 'origin/v17/dev' 2026-05-23 10:11:10 +02:00
Mads RasmussenandGitHub e06a583f1a Backoffice: Embed package root manifests into umbraco-package.ts to reduce startup requests (#22957)
* Consolidate block package into index export

* keep umbraco-package.ts and embed manifests instead

* Inline package manifests into umbraco-package

* update docs
2026-05-23 10:09:03 +02:00
Andy Butland 61cc37ad1d Revert "Entity refs render readonly when their workspace URL can't be resolved."
This reverts commit dc7b34eb58.
2026-05-23 09:42:42 +02:00
Andy Butland dc7b34eb58 Entity refs render readonly when their workspace URL can't be resolved.
Also fixes name on remove dialog.
2026-05-23 09:35:42 +02:00
Andy Butland dfe98ffa3b Disable failing link to selected content from link picker launched from RTE.
Also fixes name on remove dialog.
2026-05-23 09:16:47 +02:00
Andreas Lykke BorgandAndy Butland 6b8e8935fd Accessibility: Added missing labels to webhook details and headers (#22918)
* Added missing labels to webhoot details and headers

* Changed toggle label to aria-label to remove visible text
2026-05-22 19:04:41 +02:00
Andreas Lykke BorgandGitHub 4344fe9060 Accessibility: Added missing labels to webhook details and headers (#22918)
* Added missing labels to webhoot details and headers

* Changed toggle label to aria-label to remove visible text
2026-05-22 19:02:10 +02:00
Andy ButlandandSven Geusens 53c74efd35 Migrations: Append data-anchor value to href when missing in local link migration (closes #22860) (#22936)
* Support anchor fragments that are included in the data attribute but missing in the href when migrating local links.

* Addressed code review feedback.
2026-05-22 12:04:12 +02:00
Jacob Overgaard 485257a949 Merge branch 'v17/dev' 2026-05-22 11:23:07 +02:00
Jacob Overgaard 1c058a32d9 Merge branch 'release/17.5.0' into v17/dev 2026-05-22 11:22:13 +02:00
Andy ButlandandGitHub 12f838277c Migrations: Append data-anchor value to href when missing in local link migration (closes #22860) (#22936)
* Support anchor fragments that are included in the data attribute but missing in the href when migrating local links.

* Addressed code review feedback.
2026-05-22 11:20:05 +02:00
Jacob OvergaardandClaude Opus 4.7 1ae2a780dd Workspace Actions: Restore waiting state for buttons with additional options (closes #18670, #20593) (#22554)
* Workspace Actions: Restore waiting state for buttons with additional options

The waiting state was suppressed whenever a workspace action reported
hasAdditionalOptions() (e.g. Save and publish on multi-variant sites),
so users saw the button jump straight from idle to the success tick
with no in-flight feedback.

Always set 'waiting' on click (unless the action is a link). The
variant-picker modal still opens on top of the button, so the spinner
is effectively invisible during selection — but it becomes visible
as soon as the modal closes and the publish request is in flight.

Fixes #22551

* Workspace Actions: Spin button only while real work is in flight

Replace the eager always-set-waiting behaviour from the previous commit
with an opt-in `isPending` signal so the spinner appears only while
actual work (validation + HTTP) is happening - not while the variant
picker modal is open, and never as a spurious success tick when the
user cancels the modal.

Changes:

- Add optional `isPending: Observable<boolean>` to UmbWorkspaceAction
  and a default UmbBooleanState + protected setPending() on the base
  class. Optional + backwards compatible for external implementers.

- Add optional `onActionStarting` callback (via a shared
  UmbWorkspaceActionExecutionOptions type) to
  UmbPublishableWorkspaceContext.saveAndPublish and
  UmbSaveableWorkspaceContext.requestSave. The document publishing
  context and content detail workspace base invoke the callback at the
  join point right after the variant picker resolves (or is skipped
  for the single-variant case), so it never fires when the modal is
  cancelled.

- Wire the document save and save-and-publish actions to clear pending
  at the start of execute() and pass an onActionStarting callback that
  flips it true when work begins.

- Update the workspace action element to observe api.isPending: when
  the observable is present the waiting state is driven by the
  observable (and the success tick is suppressed if the action
  resolves without ever signalling pending - i.e. a cancellation).
  When the observable is absent the element falls back to the legacy
  eager-waiting behaviour. Failures always surface the failed tick.

Fixes #22551

* Reduce cyclomatic complexity of #onClick and _handleSave

CodeScene Code Health Review flagged two complexity issues:

- UmbWorkspaceActionElement.#onClick reached cyclomatic complexity 9
  (threshold is < 9). Extracted the api-execution branch into a new
  private #runApiAction helper so #onClick collapses to a simple
  link-vs-action dispatch.
- _handleSave was already over the threshold (14); my optional-chain
  callback invocation pushed it to 16. Moved the
  `executionOptions?.onActionStarting?.()` call into a #notifyActionStarting
  helper so the call site is a plain method call and contributes zero
  cyclomatic complexity to _handleSave.

No behavioural change.

* Reduce cyclomatic complexity of #handleSaveAndPublish

Same fix as the previous commit's #notifyActionStarting extraction in
content-detail-workspace-base: move the optional-chain callback
invocation into a private helper so #handleSaveAndPublish stays at its
pre-PR cyclomatic complexity (15) instead of degrading to 17.

No behavioural change.

* DRY: extract notifyWorkspaceActionStarting into a shared utility

Both UmbDocumentPublishingWorkspaceContext.#handleSaveAndPublish and
UmbContentDetailWorkspaceContextBase._handleSave had identical private
optional-chain callback off the host method's cyclomatic complexity.

Replace both with a single exported notifyWorkspaceActionStarting()
utility co-located with UmbWorkspaceActionExecutionOptions. This:

- Removes a duplication point between the two contexts.
- Gives future workspace context implementations a ready-made way to
  honour the optional callback without re-inventing the helper or
  paying the cyclomatic-complexity cost at the call site.

No behavioural change.

* Rename isPending -> isExecuting to mirror the execute() method

Niels suggested correlating the observable's name with the action's
`execute()` method, so the symbol set is now:

- isExecuting (observable on UmbWorkspaceAction interface)
- _isExecuting / setExecuting (UmbWorkspaceActionBase)
- #observeIsExecuting / #executionStarted (workspace-action element)
- isExecutingObserver (observer alias)

Pure rename; no behavioural change.

* Address Copilot review: lazy isExecuting, observer scope, finally reset

Five Copilot findings on PR #22554. Three real regressions + two
contract violations, all addressed:

1. UmbWorkspaceActionBase always exposing `isExecuting` made every
   existing subclass appear to opt in to the new modal-aware flow,
   suppressing waiting/success states for actions that never call
   setExecuting(true). Made `_isExecuting`/`isExecuting` lazy: only
   created on the first setExecuting() call. Opt-in subclasses call
   `setExecuting(false)` in their constructor so the observable is
   exposed before the workspace-action element reads it. Subclasses
   that don't opt in keep `isExecuting` undefined and the element
   falls back to legacy eager waiting feedback.

2. Element observation of `isExecuting` now lives inside #runApiAction
   so it tracks whichever api is actually invoked (`_actionApi ?? #api`),
   correctly handling subclasses like UmbSaveAndPreviewWorkspaceActionElement
   that swap in a different api at runtime. The shared observer alias
   replaces any previous observation on re-clicks.

3. UmbSaveWorkspaceAction and UmbDocumentSaveAndPublishWorkspaceAction
   now wrap their execute() body in try/finally and reset
   setExecuting(false) on completion so the observable honours the
   "true while execute() is performing real work, false otherwise"
   contract instead of getting stuck at true between executions.

No behavioural change for actions that already worked correctly before
this PR; the regression-prone "always exposed" behaviour is gone.

* Address Claude review: Elements gap, type placement, tests + cleanup

Three follow-ups on top of c15eb2d0bc:

1. Elements gap — UmbElementSaveAndPublishWorkspaceAction +
   UmbElementPublishingWorkspaceContext now wire through the same
   onActionStarting/notifyWorkspaceActionStarting handshake as the
   Document equivalents, so multi-variant Elements (Forms, Commerce, etc.)
   get the spinner-after-modal behaviour rather than no spinner at all.

2. Type placement — moved UmbWorkspaceActionExecutionOptions out of
   publishable-workspace-context.interface.ts into its own file so the
   saveable interface no longer has a directional dependency on the
   publishable one. Both peer contexts now import from the same neutral
   location.

3. Unit tests — added blackbox coverage for notifyWorkspaceActionStarting
   (no-op on undefined options/callback, invokes when present) and the
   UmbWorkspaceActionBase.setExecuting lazy-opt-in contract (undefined
   until first call, observable then exposed, value flips, sequential
   emissions, stable reference across calls).

Code-review cleanup applied on the same pass:

- Dropped the redundant `setExecuting(false)` at the start of execute()
  in the save and save-and-publish actions; the finally block plus
  UmbBooleanState's value-dedup already cover idempotency on retries.
- Removed an overlong block comment on `_isExecuting`; the JSDoc on
  setExecuting already documents the lazy/opt-in contract for subclasses.
- Trimmed an internal motivation comment from notify-workspace-action-
  starting.function.ts that referenced cyclomatic complexity.
- Extracted a tiny makeAction() helper in the controller test to remove
  the `{ meta: {} as never }` repetition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Workspace Actions: Align Save button state with Save & Publish (Andy review feedback)

Two related fixes addressing the variant-Save inconsistency Andy reported:

- Element catch block now only sets `failed` once `#executionStarted` is
  true. Pre-flight rejections (user cancelling a variant-picker modal,
  context-missing throws, etc.) leave the button idle, matching the
  silent-cancel path used by `#handleSaveAndPublish`. Legacy actions
  that don't opt in to `isExecuting` are unaffected because they set
  `#executionStarted = true` eagerly on click.

- `UmbDocumentWorkspaceContext._handleSave` and
  `UmbElementWorkspaceContext._handleSave` now accept and forward the
  `UmbWorkspaceActionExecutionOptions` argument to `super._handleSave`.
  The previous overrides dropped the parameter, so the
  `onActionStarting` callback supplied by `UmbSaveWorkspaceAction` never
  fired - which is why Save showed no waiting/success indicator even
  on a successful submit.

Result: Save and Save-and-publish now behave identically -
cancel = no indicator, submit = waiting then success - for both
invariant and multi-variant documents and elements.

* Docs: Document the modal-aware execution feedback contract for workspace actions

New 'Button state when the action opens a modal' subsection in
docs/workspaces.md explaining the three-piece contract:
UmbWorkspaceActionExecutionOptions + notifyWorkspaceActionStarting +
UmbWorkspaceActionBase.setExecuting. Covers third-party authoring of
modal-aware buttons, the cancel/pre-flight idle behaviour, and the
silent-parameter-drop pitfall on _handleSave overrides.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 11:00:49 +02:00
Jacob OvergaardandClaude Opus 4.7 cef6a467eb Workspace Actions: Restore waiting state for buttons with additional options (closes #18670, #20593) (#22554)
* Workspace Actions: Restore waiting state for buttons with additional options

The waiting state was suppressed whenever a workspace action reported
hasAdditionalOptions() (e.g. Save and publish on multi-variant sites),
so users saw the button jump straight from idle to the success tick
with no in-flight feedback.

Always set 'waiting' on click (unless the action is a link). The
variant-picker modal still opens on top of the button, so the spinner
is effectively invisible during selection — but it becomes visible
as soon as the modal closes and the publish request is in flight.

Fixes #22551

* Workspace Actions: Spin button only while real work is in flight

Replace the eager always-set-waiting behaviour from the previous commit
with an opt-in `isPending` signal so the spinner appears only while
actual work (validation + HTTP) is happening - not while the variant
picker modal is open, and never as a spurious success tick when the
user cancels the modal.

Changes:

- Add optional `isPending: Observable<boolean>` to UmbWorkspaceAction
  and a default UmbBooleanState + protected setPending() on the base
  class. Optional + backwards compatible for external implementers.

- Add optional `onActionStarting` callback (via a shared
  UmbWorkspaceActionExecutionOptions type) to
  UmbPublishableWorkspaceContext.saveAndPublish and
  UmbSaveableWorkspaceContext.requestSave. The document publishing
  context and content detail workspace base invoke the callback at the
  join point right after the variant picker resolves (or is skipped
  for the single-variant case), so it never fires when the modal is
  cancelled.

- Wire the document save and save-and-publish actions to clear pending
  at the start of execute() and pass an onActionStarting callback that
  flips it true when work begins.

- Update the workspace action element to observe api.isPending: when
  the observable is present the waiting state is driven by the
  observable (and the success tick is suppressed if the action
  resolves without ever signalling pending - i.e. a cancellation).
  When the observable is absent the element falls back to the legacy
  eager-waiting behaviour. Failures always surface the failed tick.

Fixes #22551

* Reduce cyclomatic complexity of #onClick and _handleSave

CodeScene Code Health Review flagged two complexity issues:

- UmbWorkspaceActionElement.#onClick reached cyclomatic complexity 9
  (threshold is < 9). Extracted the api-execution branch into a new
  private #runApiAction helper so #onClick collapses to a simple
  link-vs-action dispatch.
- _handleSave was already over the threshold (14); my optional-chain
  callback invocation pushed it to 16. Moved the
  `executionOptions?.onActionStarting?.()` call into a #notifyActionStarting
  helper so the call site is a plain method call and contributes zero
  cyclomatic complexity to _handleSave.

No behavioural change.

* Reduce cyclomatic complexity of #handleSaveAndPublish

Same fix as the previous commit's #notifyActionStarting extraction in
content-detail-workspace-base: move the optional-chain callback
invocation into a private helper so #handleSaveAndPublish stays at its
pre-PR cyclomatic complexity (15) instead of degrading to 17.

No behavioural change.

* DRY: extract notifyWorkspaceActionStarting into a shared utility

Both UmbDocumentPublishingWorkspaceContext.#handleSaveAndPublish and
UmbContentDetailWorkspaceContextBase._handleSave had identical private
#notifyActionStarting helpers introduced in this PR purely to keep the
optional-chain callback off the host method's cyclomatic complexity.

Replace both with a single exported notifyWorkspaceActionStarting()
utility co-located with UmbWorkspaceActionExecutionOptions. This:

- Removes a duplication point between the two contexts.
- Gives future workspace context implementations a ready-made way to
  honour the optional callback without re-inventing the helper or
  paying the cyclomatic-complexity cost at the call site.

No behavioural change.

* Rename isPending -> isExecuting to mirror the execute() method

Niels suggested correlating the observable's name with the action's
`execute()` method, so the symbol set is now:

- isExecuting (observable on UmbWorkspaceAction interface)
- _isExecuting / setExecuting (UmbWorkspaceActionBase)
- #observeIsExecuting / #executionStarted (workspace-action element)
- isExecutingObserver (observer alias)

Pure rename; no behavioural change.

* Address Copilot review: lazy isExecuting, observer scope, finally reset

Five Copilot findings on PR #22554. Three real regressions + two
contract violations, all addressed:

1. UmbWorkspaceActionBase always exposing `isExecuting` made every
   existing subclass appear to opt in to the new modal-aware flow,
   suppressing waiting/success states for actions that never call
   setExecuting(true). Made `_isExecuting`/`isExecuting` lazy: only
   created on the first setExecuting() call. Opt-in subclasses call
   `setExecuting(false)` in their constructor so the observable is
   exposed before the workspace-action element reads it. Subclasses
   that don't opt in keep `isExecuting` undefined and the element
   falls back to legacy eager waiting feedback.

2. Element observation of `isExecuting` now lives inside #runApiAction
   so it tracks whichever api is actually invoked (`_actionApi ?? #api`),
   correctly handling subclasses like UmbSaveAndPreviewWorkspaceActionElement
   that swap in a different api at runtime. The shared observer alias
   replaces any previous observation on re-clicks.

3. UmbSaveWorkspaceAction and UmbDocumentSaveAndPublishWorkspaceAction
   now wrap their execute() body in try/finally and reset
   setExecuting(false) on completion so the observable honours the
   "true while execute() is performing real work, false otherwise"
   contract instead of getting stuck at true between executions.

No behavioural change for actions that already worked correctly before
this PR; the regression-prone "always exposed" behaviour is gone.

* Address Claude review: Elements gap, type placement, tests + cleanup

Three follow-ups on top of c15eb2d0bc:

1. Elements gap — UmbElementSaveAndPublishWorkspaceAction +
   UmbElementPublishingWorkspaceContext now wire through the same
   onActionStarting/notifyWorkspaceActionStarting handshake as the
   Document equivalents, so multi-variant Elements (Forms, Commerce, etc.)
   get the spinner-after-modal behaviour rather than no spinner at all.

2. Type placement — moved UmbWorkspaceActionExecutionOptions out of
   publishable-workspace-context.interface.ts into its own file so the
   saveable interface no longer has a directional dependency on the
   publishable one. Both peer contexts now import from the same neutral
   location.

3. Unit tests — added blackbox coverage for notifyWorkspaceActionStarting
   (no-op on undefined options/callback, invokes when present) and the
   UmbWorkspaceActionBase.setExecuting lazy-opt-in contract (undefined
   until first call, observable then exposed, value flips, sequential
   emissions, stable reference across calls).

Code-review cleanup applied on the same pass:

- Dropped the redundant `setExecuting(false)` at the start of execute()
  in the save and save-and-publish actions; the finally block plus
  UmbBooleanState's value-dedup already cover idempotency on retries.
- Removed an overlong block comment on `_isExecuting`; the JSDoc on
  setExecuting already documents the lazy/opt-in contract for subclasses.
- Trimmed an internal motivation comment from notify-workspace-action-
  starting.function.ts that referenced cyclomatic complexity.
- Extracted a tiny makeAction() helper in the controller test to remove
  the `{ meta: {} as never }` repetition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Workspace Actions: Align Save button state with Save & Publish (Andy review feedback)

Two related fixes addressing the variant-Save inconsistency Andy reported:

- Element catch block now only sets `failed` once `#executionStarted` is
  true. Pre-flight rejections (user cancelling a variant-picker modal,
  context-missing throws, etc.) leave the button idle, matching the
  silent-cancel path used by `#handleSaveAndPublish`. Legacy actions
  that don't opt in to `isExecuting` are unaffected because they set
  `#executionStarted = true` eagerly on click.

- `UmbDocumentWorkspaceContext._handleSave` and
  `UmbElementWorkspaceContext._handleSave` now accept and forward the
  `UmbWorkspaceActionExecutionOptions` argument to `super._handleSave`.
  The previous overrides dropped the parameter, so the
  `onActionStarting` callback supplied by `UmbSaveWorkspaceAction` never
  fired - which is why Save showed no waiting/success indicator even
  on a successful submit.

Result: Save and Save-and-publish now behave identically -
cancel = no indicator, submit = waiting then success - for both
invariant and multi-variant documents and elements.

* Docs: Document the modal-aware execution feedback contract for workspace actions

New 'Button state when the action opens a modal' subsection in
docs/workspaces.md explaining the three-piece contract:
UmbWorkspaceActionExecutionOptions + notifyWorkspaceActionStarting +
UmbWorkspaceActionBase.setExecuting. Covers third-party authoring of
modal-aware buttons, the cancel/pre-flight idle behaviour, and the
silent-parameter-drop pitfall on _handleSave overrides.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 10:56:22 +02:00
c542b1b4fd Workspace Actions: Restore waiting state for buttons with additional options (closes #18670, #20593) (#22554)
* Workspace Actions: Restore waiting state for buttons with additional options

The waiting state was suppressed whenever a workspace action reported
hasAdditionalOptions() (e.g. Save and publish on multi-variant sites),
so users saw the button jump straight from idle to the success tick
with no in-flight feedback.

Always set 'waiting' on click (unless the action is a link). The
variant-picker modal still opens on top of the button, so the spinner
is effectively invisible during selection — but it becomes visible
as soon as the modal closes and the publish request is in flight.

Fixes #22551

* Workspace Actions: Spin button only while real work is in flight

Replace the eager always-set-waiting behaviour from the previous commit
with an opt-in `isPending` signal so the spinner appears only while
actual work (validation + HTTP) is happening - not while the variant
picker modal is open, and never as a spurious success tick when the
user cancels the modal.

Changes:

- Add optional `isPending: Observable<boolean>` to UmbWorkspaceAction
  and a default UmbBooleanState + protected setPending() on the base
  class. Optional + backwards compatible for external implementers.

- Add optional `onActionStarting` callback (via a shared
  UmbWorkspaceActionExecutionOptions type) to
  UmbPublishableWorkspaceContext.saveAndPublish and
  UmbSaveableWorkspaceContext.requestSave. The document publishing
  context and content detail workspace base invoke the callback at the
  join point right after the variant picker resolves (or is skipped
  for the single-variant case), so it never fires when the modal is
  cancelled.

- Wire the document save and save-and-publish actions to clear pending
  at the start of execute() and pass an onActionStarting callback that
  flips it true when work begins.

- Update the workspace action element to observe api.isPending: when
  the observable is present the waiting state is driven by the
  observable (and the success tick is suppressed if the action
  resolves without ever signalling pending - i.e. a cancellation).
  When the observable is absent the element falls back to the legacy
  eager-waiting behaviour. Failures always surface the failed tick.

Fixes #22551

* Reduce cyclomatic complexity of #onClick and _handleSave

CodeScene Code Health Review flagged two complexity issues:

- UmbWorkspaceActionElement.#onClick reached cyclomatic complexity 9
  (threshold is < 9). Extracted the api-execution branch into a new
  private #runApiAction helper so #onClick collapses to a simple
  link-vs-action dispatch.
- _handleSave was already over the threshold (14); my optional-chain
  callback invocation pushed it to 16. Moved the
  `executionOptions?.onActionStarting?.()` call into a #notifyActionStarting
  helper so the call site is a plain method call and contributes zero
  cyclomatic complexity to _handleSave.

No behavioural change.

* Reduce cyclomatic complexity of #handleSaveAndPublish

Same fix as the previous commit's #notifyActionStarting extraction in
content-detail-workspace-base: move the optional-chain callback
invocation into a private helper so #handleSaveAndPublish stays at its
pre-PR cyclomatic complexity (15) instead of degrading to 17.

No behavioural change.

* DRY: extract notifyWorkspaceActionStarting into a shared utility

Both UmbDocumentPublishingWorkspaceContext.#handleSaveAndPublish and
UmbContentDetailWorkspaceContextBase._handleSave had identical private
#notifyActionStarting helpers introduced in this PR purely to keep the
optional-chain callback off the host method's cyclomatic complexity.

Replace both with a single exported notifyWorkspaceActionStarting()
utility co-located with UmbWorkspaceActionExecutionOptions. This:

- Removes a duplication point between the two contexts.
- Gives future workspace context implementations a ready-made way to
  honour the optional callback without re-inventing the helper or
  paying the cyclomatic-complexity cost at the call site.

No behavioural change.

* Rename isPending -> isExecuting to mirror the execute() method

Niels suggested correlating the observable's name with the action's
`execute()` method, so the symbol set is now:

- isExecuting (observable on UmbWorkspaceAction interface)
- _isExecuting / setExecuting (UmbWorkspaceActionBase)
- #observeIsExecuting / #executionStarted (workspace-action element)
- isExecutingObserver (observer alias)

Pure rename; no behavioural change.

* Address Copilot review: lazy isExecuting, observer scope, finally reset

Five Copilot findings on PR #22554. Three real regressions + two
contract violations, all addressed:

1. UmbWorkspaceActionBase always exposing `isExecuting` made every
   existing subclass appear to opt in to the new modal-aware flow,
   suppressing waiting/success states for actions that never call
   setExecuting(true). Made `_isExecuting`/`isExecuting` lazy: only
   created on the first setExecuting() call. Opt-in subclasses call
   `setExecuting(false)` in their constructor so the observable is
   exposed before the workspace-action element reads it. Subclasses
   that don't opt in keep `isExecuting` undefined and the element
   falls back to legacy eager waiting feedback.

2. Element observation of `isExecuting` now lives inside #runApiAction
   so it tracks whichever api is actually invoked (`_actionApi ?? #api`),
   correctly handling subclasses like UmbSaveAndPreviewWorkspaceActionElement
   that swap in a different api at runtime. The shared observer alias
   replaces any previous observation on re-clicks.

3. UmbSaveWorkspaceAction and UmbDocumentSaveAndPublishWorkspaceAction
   now wrap their execute() body in try/finally and reset
   setExecuting(false) on completion so the observable honours the
   "true while execute() is performing real work, false otherwise"
   contract instead of getting stuck at true between executions.

No behavioural change for actions that already worked correctly before
this PR; the regression-prone "always exposed" behaviour is gone.

* Address Claude review: Elements gap, type placement, tests + cleanup

Three follow-ups on top of c15eb2d0bc:

1. Elements gap — UmbElementSaveAndPublishWorkspaceAction +
   UmbElementPublishingWorkspaceContext now wire through the same
   onActionStarting/notifyWorkspaceActionStarting handshake as the
   Document equivalents, so multi-variant Elements (Forms, Commerce, etc.)
   get the spinner-after-modal behaviour rather than no spinner at all.

2. Type placement — moved UmbWorkspaceActionExecutionOptions out of
   publishable-workspace-context.interface.ts into its own file so the
   saveable interface no longer has a directional dependency on the
   publishable one. Both peer contexts now import from the same neutral
   location.

3. Unit tests — added blackbox coverage for notifyWorkspaceActionStarting
   (no-op on undefined options/callback, invokes when present) and the
   UmbWorkspaceActionBase.setExecuting lazy-opt-in contract (undefined
   until first call, observable then exposed, value flips, sequential
   emissions, stable reference across calls).

Code-review cleanup applied on the same pass:

- Dropped the redundant `setExecuting(false)` at the start of execute()
  in the save and save-and-publish actions; the finally block plus
  UmbBooleanState's value-dedup already cover idempotency on retries.
- Removed an overlong block comment on `_isExecuting`; the JSDoc on
  setExecuting already documents the lazy/opt-in contract for subclasses.
- Trimmed an internal motivation comment from notify-workspace-action-
  starting.function.ts that referenced cyclomatic complexity.
- Extracted a tiny makeAction() helper in the controller test to remove
  the `{ meta: {} as never }` repetition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Workspace Actions: Align Save button state with Save & Publish (Andy review feedback)

Two related fixes addressing the variant-Save inconsistency Andy reported:

- Element catch block now only sets `failed` once `#executionStarted` is
  true. Pre-flight rejections (user cancelling a variant-picker modal,
  context-missing throws, etc.) leave the button idle, matching the
  silent-cancel path used by `#handleSaveAndPublish`. Legacy actions
  that don't opt in to `isExecuting` are unaffected because they set
  `#executionStarted = true` eagerly on click.

- `UmbDocumentWorkspaceContext._handleSave` and
  `UmbElementWorkspaceContext._handleSave` now accept and forward the
  `UmbWorkspaceActionExecutionOptions` argument to `super._handleSave`.
  The previous overrides dropped the parameter, so the
  `onActionStarting` callback supplied by `UmbSaveWorkspaceAction` never
  fired - which is why Save showed no waiting/success indicator even
  on a successful submit.

Result: Save and Save-and-publish now behave identically -
cancel = no indicator, submit = waiting then success - for both
invariant and multi-variant documents and elements.

* Docs: Document the modal-aware execution feedback contract for workspace actions

New 'Button state when the action opens a modal' subsection in
docs/workspaces.md explaining the three-piece contract:
UmbWorkspaceActionExecutionOptions + notifyWorkspaceActionStarting +
UmbWorkspaceActionBase.setExecuting. Covers third-party authoring of
modal-aware buttons, the cancel/pre-flight idle behaviour, and the
silent-parameter-drop pitfall on _handleSave overrides.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 08:32:48 +00:00
Jacob OvergaardandClaude Opus 4.7 26232e0276 Backoffice: Coalesce small Rollup chunks across all workspaces (AB#67983) (#22896)
* Backoffice: Coalesce small Rollup chunks across all workspaces (AB#67983)

Set experimentalMinChunkSize=10_000 as the default in the shared Vite
helper. Every workspace inherits the coalescing automatically; the
threshold can still be overridden per workspace (pass 0 to disable).

Impact on dist-cms output:
- packages/core .js files: 981 -> 272 (-72%)
- All workspaces combined .js files: 2194 -> 1401 (-36%)
- Welcome dashboard .js requests: 510 -> 497 (-2.5%)
- packages/ufm requests in particular: 23 -> 12 (-48%)
- Gzipped bundle total: -1.2%
- Raw bytes: +1.4% (small overhead from merged chunks; gzip wins it back)

All entry chunks are preserved, so every public
@umbraco-cms/backoffice/<sub> import keeps resolving without changes
to package.json exports or tsconfig paths.

Further consolidation (collapsing core's per-subpath entries into a
single bundle with stubs) was prototyped but hits a TDZ cycle between
the eager entry and its dynamic-import descendants. Tracked for v18,
not part of this change.

* Backoffice: Normalise umbraco-package + manifests shapes (AB#67983)

Aligns the two outliers with the conventions used by the other 38
first-party packages:

- documents/umbraco-package.ts now uses the lazy bundle pattern
  (type: 'bundle', js: () => import('./manifests.js')) instead of
  eagerly importing manifests at module evaluation. The bundle
  initializer auto-loads the manifests at boot, so behaviour is
  unchanged.
- umbraco-news/manifests.ts now exports `manifests: Array<...>`
  instead of a bare `dashboard` object. The bundle initializer
  enumerates exports regardless of name, so behaviour is unchanged.

Preparatory cleanup so future build-time manifest aggregation can
treat every workspace uniformly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 09:39:06 +02:00
Jacob Overgaard 767fafe06d Merge remote-tracking branch 'origin/v17/dev' 2026-05-22 09:38:31 +02:00
Jacob OvergaardandClaude Opus 4.7 04f0e229c7 Backoffice: Coalesce small Rollup chunks across all workspaces (AB#67983) (#22896)
* Backoffice: Coalesce small Rollup chunks across all workspaces (AB#67983)

Set experimentalMinChunkSize=10_000 as the default in the shared Vite
helper. Every workspace inherits the coalescing automatically; the
threshold can still be overridden per workspace (pass 0 to disable).

Impact on dist-cms output:
- packages/core .js files: 981 -> 272 (-72%)
- All workspaces combined .js files: 2194 -> 1401 (-36%)
- Welcome dashboard .js requests: 510 -> 497 (-2.5%)
- packages/ufm requests in particular: 23 -> 12 (-48%)
- Gzipped bundle total: -1.2%
- Raw bytes: +1.4% (small overhead from merged chunks; gzip wins it back)

All entry chunks are preserved, so every public
@umbraco-cms/backoffice/<sub> import keeps resolving without changes
to package.json exports or tsconfig paths.

Further consolidation (collapsing core's per-subpath entries into a
single bundle with stubs) was prototyped but hits a TDZ cycle between
the eager entry and its dynamic-import descendants. Tracked for v18,
not part of this change.

* Backoffice: Normalise umbraco-package + manifests shapes (AB#67983)

Aligns the two outliers with the conventions used by the other 38
first-party packages:

- documents/umbraco-package.ts now uses the lazy bundle pattern
  (type: 'bundle', js: () => import('./manifests.js')) instead of
  eagerly importing manifests at module evaluation. The bundle
  initializer auto-loads the manifests at boot, so behaviour is
  unchanged.
- umbraco-news/manifests.ts now exports `manifests: Array<...>`
  instead of a bare `dashboard` object. The bundle initializer
  enumerates exports regardless of name, so behaviour is unchanged.

Preparatory cleanup so future build-time manifest aggregation can
treat every workspace uniformly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 09:35:44 +02:00
5d76706553 Backoffice: Coalesce small Rollup chunks across all workspaces (AB#67983) (#22896)
* Backoffice: Coalesce small Rollup chunks across all workspaces (AB#67983)

Set experimentalMinChunkSize=10_000 as the default in the shared Vite
helper. Every workspace inherits the coalescing automatically; the
threshold can still be overridden per workspace (pass 0 to disable).

Impact on dist-cms output:
- packages/core .js files: 981 -> 272 (-72%)
- All workspaces combined .js files: 2194 -> 1401 (-36%)
- Welcome dashboard .js requests: 510 -> 497 (-2.5%)
- packages/ufm requests in particular: 23 -> 12 (-48%)
- Gzipped bundle total: -1.2%
- Raw bytes: +1.4% (small overhead from merged chunks; gzip wins it back)

All entry chunks are preserved, so every public
@umbraco-cms/backoffice/<sub> import keeps resolving without changes
to package.json exports or tsconfig paths.

Further consolidation (collapsing core's per-subpath entries into a
single bundle with stubs) was prototyped but hits a TDZ cycle between
the eager entry and its dynamic-import descendants. Tracked for v18,
not part of this change.

* Backoffice: Normalise umbraco-package + manifests shapes (AB#67983)

Aligns the two outliers with the conventions used by the other 38
first-party packages:

- documents/umbraco-package.ts now uses the lazy bundle pattern
  (type: 'bundle', js: () => import('./manifests.js')) instead of
  eagerly importing manifests at module evaluation. The bundle
  initializer auto-loads the manifests at boot, so behaviour is
  unchanged.
- umbraco-news/manifests.ts now exports `manifests: Array<...>`
  instead of a bare `dashboard` object. The bundle initializer
  enumerates exports regardless of name, so behaviour is unchanged.

Preparatory cleanup so future build-time manifest aggregation can
treat every workspace uniformly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 09:28:31 +02:00
Mads RasmussenandGitHub 1fdcb835bc Devops: Report bidirectional import detection for both Core and Packages modules (#22938)
report bidirectional imports for core modules
2026-05-22 07:29:37 +02:00
Mads RasmussenandGitHub 6b3bdb59b7 Backoffice: Swap relative imports to @umbraco-cms/backoffice module imports in core packages (#22942)
Use @umbraco-cms/backoffice imports

Replace numerous relative/internal import paths with centralized '@umbraco-cms/backoffice' package entry points across core modules.This consolidates exports, simplifies import paths.
2026-05-22 07:24:39 +02:00
Andy Butland 216fee987b Added a TODO for a future major. 2026-05-22 06:44:36 +02:00
Andy Butland 36ea0a494d Bump version to 18.0.0-rc1. 2026-05-21 19:45:51 +02:00
Andy Butland ca6a32088a Merge branch 'v17/dev' 2026-05-21 19:41:41 +02:00
Andy ButlandandClaude Opus 4.6 d6f6e31c68 Background Jobs: Rewrite RecurringHostedServiceBase with SemaphoreSlim and add signalling support (#22331)
* Compute next delay to compensate for time drift

* Use SemaphoreSlim to properly handle exceptions, cancellation tokens and triggering immediate executions

* Add RecurringBackgroundJobBase to contain default values and hide obsoleted method

* Add NextExecutionStrategy parameter to adjust the schedule after triggered executions

* Add TriggerExecution methods to RecurringBackgroundJobHostedServiceRunner

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Handle cancellation (application shutdown) and publish RecurringBackgroundJobCanceledNotification

* Match hosted services by Type instead of type name string

* Extract shared helper for TriggerExecution tests

* Clear trigger state when initial delay is interrupted

* Clear _nextExecutionSkipOnOvershoot unconditionally

* Combine ComputeNextDelay tests

* Consolidate trigger state into an immutable record for thread safety

* Use ConcurrentDictionary for thread-safe hosted service lookup

* Remove hosted services from dictionary on stop

* Fix API compatibility errors

* Removed unneeded using.

* Register RecurringBackgroundJobHostedServiceRunner as resolvable singleton

* Remove failed hosted service from dictionary when StartAsync throws

* Use semaphore signaling instead of Task.Delay in trigger tests

Use semaphore signaling instead of Task.Delay in trigger tests 2

* Inject TimeProvider into RecurringHostedServiceBase for deterministic testing

Fix timeprovider

* Use DelayCalculator.GetDelay instead of RecurringHostedServiceBase.GetDelay

* Fix Exception_In_PerformExecuteAsync_Does_Not_Kill_Loop test

* Avoid disposing period-change CTS while wait loop may still reference it

* Configure IEventMessagesFactory mock to return real EventMessages

* Clarify TriggerExecution(TimeSpan) docs and add ChangePeriod test

* Validate period is positive and use GetOrAdd to avoid creating unused hosted services

* Set up Period and Delay on mock job to satisfy constructor validation

* Ensure PeriodChanged event is unsubscribed again

* Fix trigger state race, simplify ReleaseSignal, and add canceled notification test

Fix trigger state

* Use Interlocked for _period reads/writes and implement thread-safe dispose pattern

* Remove hosted service from dictionary before stopping to prevent triggering during shutdown

* Replace Task.Yield with semaphore timeouts in negative assertions

* Tidy RecurringBackgroundJobBase docs and runner error handling

* Wait IgnoredDelay after ignored execution to prevent tight looping when Period is short or zero

* Add IRecurringBackgroundJobTrigger<TJob> for opt-in job triggering

* Register IRecurringBackgroundJobTrigger as open generic and drop AddTriggerableRecurringBackgroundJob

* Fix and add parameter validation

* Allow Timeout.InfiniteTimeSpan as Period for manual-trigger-only recurring jobs

* Migrate built-in jobs to RecurringBackgroundJobBase and require ITriggerableRecurringBackgroundJob in runner trigger overloads

* Support infinite Delay and honor TriggerExecution(TimeSpan) issued during the initial delay

* Handle edge case of backoff via InfiniteTimeSpan.

* Refactored large method.

* Added clarifying documentation.

* Suppress ExecutionContext flow when starting the recurring background loop, restoring previous timer behaviour.

* Relocate Suppress ExecutionContext flow to avoid package validation error.

* Align IRecurringBackgroundJobTrigger generic type constraint with AddRecurringBackgroundJob

* Rename ApplyTriggerState to ComputeNextDelayFromTriggerState

* Allow Timeout.InfiniteTimeSpan as IgnoredDelay to fully disable a job for the remaining application lifecycle

* Fix generic type constraint

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-21 19:40:54 +02:00
65ab1c0b2b Background Jobs: Rewrite RecurringHostedServiceBase with SemaphoreSlim and add signalling support (#22331)
* Compute next delay to compensate for time drift

* Use SemaphoreSlim to properly handle exceptions, cancellation tokens and triggering immediate executions

* Add RecurringBackgroundJobBase to contain default values and hide obsoleted method

* Add NextExecutionStrategy parameter to adjust the schedule after triggered executions

* Add TriggerExecution methods to RecurringBackgroundJobHostedServiceRunner

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Handle cancellation (application shutdown) and publish RecurringBackgroundJobCanceledNotification

* Match hosted services by Type instead of type name string

* Extract shared helper for TriggerExecution tests

* Clear trigger state when initial delay is interrupted

* Clear _nextExecutionSkipOnOvershoot unconditionally

* Combine ComputeNextDelay tests

* Consolidate trigger state into an immutable record for thread safety

* Use ConcurrentDictionary for thread-safe hosted service lookup

* Remove hosted services from dictionary on stop

* Fix API compatibility errors

* Removed unneeded using.

* Register RecurringBackgroundJobHostedServiceRunner as resolvable singleton

* Remove failed hosted service from dictionary when StartAsync throws

* Use semaphore signaling instead of Task.Delay in trigger tests

Use semaphore signaling instead of Task.Delay in trigger tests 2

* Inject TimeProvider into RecurringHostedServiceBase for deterministic testing

Fix timeprovider

* Use DelayCalculator.GetDelay instead of RecurringHostedServiceBase.GetDelay

* Fix Exception_In_PerformExecuteAsync_Does_Not_Kill_Loop test

* Avoid disposing period-change CTS while wait loop may still reference it

* Configure IEventMessagesFactory mock to return real EventMessages

* Clarify TriggerExecution(TimeSpan) docs and add ChangePeriod test

* Validate period is positive and use GetOrAdd to avoid creating unused hosted services

* Set up Period and Delay on mock job to satisfy constructor validation

* Ensure PeriodChanged event is unsubscribed again

* Fix trigger state race, simplify ReleaseSignal, and add canceled notification test

Fix trigger state

* Use Interlocked for _period reads/writes and implement thread-safe dispose pattern

* Remove hosted service from dictionary before stopping to prevent triggering during shutdown

* Replace Task.Yield with semaphore timeouts in negative assertions

* Tidy RecurringBackgroundJobBase docs and runner error handling

* Wait IgnoredDelay after ignored execution to prevent tight looping when Period is short or zero

* Add IRecurringBackgroundJobTrigger<TJob> for opt-in job triggering

* Register IRecurringBackgroundJobTrigger as open generic and drop AddTriggerableRecurringBackgroundJob

* Fix and add parameter validation

* Allow Timeout.InfiniteTimeSpan as Period for manual-trigger-only recurring jobs

* Migrate built-in jobs to RecurringBackgroundJobBase and require ITriggerableRecurringBackgroundJob in runner trigger overloads

* Support infinite Delay and honor TriggerExecution(TimeSpan) issued during the initial delay

* Handle edge case of backoff via InfiniteTimeSpan.

* Refactored large method.

* Added clarifying documentation.

* Suppress ExecutionContext flow when starting the recurring background loop, restoring previous timer behaviour.

* Relocate Suppress ExecutionContext flow to avoid package validation error.

* Align IRecurringBackgroundJobTrigger generic type constraint with AddRecurringBackgroundJob

* Rename ApplyTriggerState to ComputeNextDelayFromTriggerState

* Allow Timeout.InfiniteTimeSpan as IgnoredDelay to fully disable a job for the remaining application lifecycle

* Fix generic type constraint

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-21 19:39:21 +02:00
a54769758b Background Jobs: Rewrite RecurringHostedServiceBase with SemaphoreSlim and add signalling support (#22331)
* Compute next delay to compensate for time drift

* Use SemaphoreSlim to properly handle exceptions, cancellation tokens and triggering immediate executions

* Add RecurringBackgroundJobBase to contain default values and hide obsoleted method

* Add NextExecutionStrategy parameter to adjust the schedule after triggered executions

* Add TriggerExecution methods to RecurringBackgroundJobHostedServiceRunner

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Handle cancellation (application shutdown) and publish RecurringBackgroundJobCanceledNotification

* Match hosted services by Type instead of type name string

* Extract shared helper for TriggerExecution tests

* Clear trigger state when initial delay is interrupted

* Clear _nextExecutionSkipOnOvershoot unconditionally

* Combine ComputeNextDelay tests

* Consolidate trigger state into an immutable record for thread safety

* Use ConcurrentDictionary for thread-safe hosted service lookup

* Remove hosted services from dictionary on stop

* Fix API compatibility errors

* Removed unneeded using.

* Register RecurringBackgroundJobHostedServiceRunner as resolvable singleton

* Remove failed hosted service from dictionary when StartAsync throws

* Use semaphore signaling instead of Task.Delay in trigger tests

Use semaphore signaling instead of Task.Delay in trigger tests 2

* Inject TimeProvider into RecurringHostedServiceBase for deterministic testing

Fix timeprovider

* Use DelayCalculator.GetDelay instead of RecurringHostedServiceBase.GetDelay

* Fix Exception_In_PerformExecuteAsync_Does_Not_Kill_Loop test

* Avoid disposing period-change CTS while wait loop may still reference it

* Configure IEventMessagesFactory mock to return real EventMessages

* Clarify TriggerExecution(TimeSpan) docs and add ChangePeriod test

* Validate period is positive and use GetOrAdd to avoid creating unused hosted services

* Set up Period and Delay on mock job to satisfy constructor validation

* Ensure PeriodChanged event is unsubscribed again

* Fix trigger state race, simplify ReleaseSignal, and add canceled notification test

Fix trigger state

* Use Interlocked for _period reads/writes and implement thread-safe dispose pattern

* Remove hosted service from dictionary before stopping to prevent triggering during shutdown

* Replace Task.Yield with semaphore timeouts in negative assertions

* Tidy RecurringBackgroundJobBase docs and runner error handling

* Wait IgnoredDelay after ignored execution to prevent tight looping when Period is short or zero

* Add IRecurringBackgroundJobTrigger<TJob> for opt-in job triggering

* Register IRecurringBackgroundJobTrigger as open generic and drop AddTriggerableRecurringBackgroundJob

* Fix and add parameter validation

* Allow Timeout.InfiniteTimeSpan as Period for manual-trigger-only recurring jobs

* Migrate built-in jobs to RecurringBackgroundJobBase and require ITriggerableRecurringBackgroundJob in runner trigger overloads

* Support infinite Delay and honor TriggerExecution(TimeSpan) issued during the initial delay

* Handle edge case of backoff via InfiniteTimeSpan.

* Refactored large method.

* Added clarifying documentation.

* Suppress ExecutionContext flow when starting the recurring background loop, restoring previous timer behaviour.

* Relocate Suppress ExecutionContext flow to avoid package validation error.

* Align IRecurringBackgroundJobTrigger generic type constraint with AddRecurringBackgroundJob

* Rename ApplyTriggerState to ComputeNextDelayFromTriggerState

* Allow Timeout.InfiniteTimeSpan as IgnoredDelay to fully disable a job for the remaining application lifecycle

* Fix generic type constraint

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-21 19:36:04 +02:00
Andy Butland 62db2c06bb Merge branch 'v17/dev' 2026-05-21 19:07:14 +02:00
Andreas Lykke BorgandAndy Butland ad681cfde3 Image Cropper: Improve contrast of append label in crop options editor (closes #22878) (#22917)
Improve contrast of input append label in image crops editor
2026-05-21 19:06:36 +02:00
Andreas Lykke BorgandAndy Butland 1616997409 Image Cropper: Improve contrast of append label in crop options editor (closes #22878) (#22917)
Improve contrast of input append label in image crops editor
2026-05-21 19:06:01 +02:00
Andreas Lykke BorgandGitHub 609b74b475 Image Cropper: Improve contrast of append label in crop options editor (closes #22878) (#22917)
Improve contrast of input append label in image crops editor
2026-05-21 19:05:33 +02:00
Andy Butland e756e40003 Fixed front-end build issue after merge. 2026-05-21 18:45:09 +02:00
Andy Butland b8d6c83d53 Merge branch 'v17/dev' 2026-05-21 18:13:55 +02:00
Engiber LozadaandAndy Butland 0e7eb11c60 Block Grid: Fix inline create button width not updating on workspace resize (closes #22527) (#22928)
* Add ResizeObserver for inline create buttons

* Disconnect layout resize observer on destroy

* Initialize ResizeObserver and simplify cleanup

* Remove optional chaining on layout observer disconnect
2026-05-21 18:13:10 +02:00
Engiber LozadaandAndy Butland 63289e22cb Block Grid: Fix inline create button width not updating on workspace resize (closes #22527) (#22928)
* Add ResizeObserver for inline create buttons

* Disconnect layout resize observer on destroy

* Initialize ResizeObserver and simplify cleanup

* Remove optional chaining on layout observer disconnect
2026-05-21 18:12:23 +02:00
Engiber LozadaandGitHub 82b2991a18 Block Grid: Fix inline create button width not updating on workspace resize (closes #22527) (#22928)
* Add ResizeObserver for inline create buttons

* Disconnect layout resize observer on destroy

* Initialize ResizeObserver and simplify cleanup

* Remove optional chaining on layout observer disconnect
2026-05-21 18:11:24 +02:00
Andy Butland 0f357f595e Merge branch 'v17/dev' 2026-05-21 18:01:17 +02:00
Andy Butland 721cf53d40 Fix styling of redirect tracker enabled/disabled icon. 2026-05-21 17:59:27 +02:00
Andy Butland f8ba3d8cfc Merge branch 'release/17.5.0' into v17/dev 2026-05-21 17:41:20 +02:00
Andy ButlandandLan Nguyen Thuy 7f832d261d Reset password: Add inline validation messaging for password pattern requirements (#22880)
* add custom validation for password input in reset password

* update remove invalid listeners in disconnectedCallback

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-05-21 17:34:05 +02:00
Andy ButlandandLan Nguyen Thuy 3523fbbed2 Reset password: Add inline validation messaging for password pattern requirements (#22880)
* add custom validation for password input in reset password

* update remove invalid listeners in disconnectedCallback

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-05-21 17:19:05 +02:00
Andy Butland 0116ddb81d Fixed code styling. 2026-05-21 17:16:54 +02:00
Andy Butland a4a2d4ee35 Fixed incorrect documentation. 2026-05-21 17:16:46 +02:00
4ecbface60 Reset password: Add inline validation messaging for password pattern requirements (#22880)
* add custom validation for password input in reset password

* update remove invalid listeners in disconnectedCallback

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-05-21 17:13:35 +02:00
Lee KelleherandGitHub 22340a40f8 Global Elements: Trashed item restore, checks "Move" permission (#22925) 2026-05-21 15:08:48 +00:00
Lee KelleherandGitHub 831b1ac7ad Element Picker: fixes "Not Found" name on removal prompt (#22922)
* Element Tree Picker Data Source: adds item data resolver

This follows PR #22915, which fixes the Entity Data Picker's
removal confirmation message with the entity's name.

* Adds support for `UmbElementFolderItemDataResolver`
2026-05-21 15:07:45 +00:00
Andy ButlandandGitHub 9276dd757a Cache: Invalidate element GUID-keyed cache on delete (closes #22911) (#22940)
Fix GUID key lookup for clearing the element by key cache after deletion.
2026-05-21 16:52:33 +02:00
Lee KelleherandGitHub 73195ca7a3 Global Elements: Workspace hotfix for 'Unique is missing' warning (#22935)
fix(elements): resolve 'Unique is missing' race when navigating element workspaces
2026-05-21 15:32:25 +02:00
Andy Butland 9c6550207d Fix failing unit tests. 2026-05-21 15:03:47 +02:00
Jacob Overgaard 80e6b481c0 Merge branch 'release/18.0' 2026-05-21 12:38:06 +02:00
Jacob OvergaardandClaude Opus 4.7 79065052c6 Mocks: Add missing allowedInLibrary and noAccess to document type mock data
Backfills the two required properties on the seven mock document type
entries that were missing them, so the file type-checks against
DocumentTypeResponseModel and DocumentTypeTreeItemResponseModel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 12:33:44 +02:00
Jacob Overgaard e3bee4cdb3 fix: exports condition configs and fixes test imports 2026-05-21 12:28:40 +02:00
Jacob Overgaard 68a633047e Test: adds 'mocha' and 'chai' as types for tsconfig (#22889)
fix(test): adds 'mocha' and 'chai' as types for tsconfig
2026-05-21 12:23:22 +02:00
Mads Rasmussenandleekelleher 06c2055e22 Collections: Replace direct filter pass-through in collection server data sources (#22921)
Pass explicit skip/take to collection services

(cherry picked from commit f79e9586b4)
2026-05-21 09:30:08 +01:00
Mads Rasmussenandleekelleher 55e5ae789d Entity Data Picker: Fix "Not Found" in remove dialog for entities without a top-level name (#22915)
* Add item data resolver support to picker data sources

* add js docs

* remove duplicated fallback logic

* wip unit tests of requestItemName method

* Use DocumentVariantStateModel in mock documents to fix compiler

* Update input-entity-data.context.ts

* Update input-entity-data.context.test.ts

(cherry picked from commit c74a58246f)
2026-05-21 09:27:42 +01:00
Mads RasmussenandGitHub f79e9586b4 Collections: Replace direct filter pass-through in collection server data sources (#22921)
Pass explicit skip/take to collection services
2026-05-21 09:18:36 +01:00
nikolajlauridsen 60948d197a Merge branch 'v17/dev'
# Conflicts:
#	src/Umbraco.Core/Services/DocumentUrlService.cs
2026-05-21 10:15:13 +02:00
Mads RasmussenandGitHub c74a58246f Entity Data Picker: Fix "Not Found" in remove dialog for entities without a top-level name (#22915)
* Add item data resolver support to picker data sources

* add js docs

* remove duplicated fallback logic

* wip unit tests of requestItemName method

* Use DocumentVariantStateModel in mock documents to fix compiler

* Update input-entity-data.context.ts

* Update input-entity-data.context.test.ts
2026-05-21 09:13:45 +01:00
nikolajlauridsen 62048dc5a8 Merge branch 'release/17.4.2' into release/18.0
# Conflicts:
#	src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs
#	src/Umbraco.Core/Services/DocumentUrlService.cs
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	src/Umbraco.Web.UI.Client/src/external/uui/package.json
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
#	tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PublishedContent/PublishedValueFallbackTests.cs
#	version.json
2026-05-21 09:25:44 +02:00
nikolajlauridsen 06b15157cf Merge branch 'release/17.4.2' into release/17.5.0
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
#	version.json
2026-05-21 09:18:11 +02:00
nikolajlauridsen 82f7830d26 Merge branch 'release/17.4.2' into v17/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
#	version.json
2026-05-21 09:16:39 +02:00
Andy Butland 337cd32258 Merge branch 'v17/dev' 2026-05-21 07:45:20 +02:00
MoleandGitHub b87d519bf2 Cache: Only write to url table on a single server in load balanced environments to remove lock contention (#22890)
* Move database writes out of cache refreshers

* add tests

* Fix up tests
2026-05-20 17:08:33 +02:00
Jacob OvergaardandClaude Opus 4.7 247935cc38 Tests: Fix unit tests broken by sync element fast-path and lazy property materialization
- ElementPickerValueConverterTests: also stub the new synchronous IPublishedElementCache.GetById,
  since Moq does not execute default interface implementations.
- PropertyCacheLevelTests.CacheUnknownTest: access a property inside Assert.Throws to trigger the
  now-lazy property wrapper materialization.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:51:01 +02:00
Jacob OvergaardandGitHub b9c4c5be74 Test: adds 'mocha' and 'chai' as types for tsconfig (#22889)
fix(test): adds 'mocha' and 'chai' as types for tsconfig
2026-05-20 10:59:31 +01:00
Andy Butland d9ea76857b Merge branch 'release/18.0' of https://github.com/umbraco/Umbraco-CMS into release/18.0 2026-05-20 11:01:24 +02:00
Laura NetoandGitHub 2f520981aa Extension template: Use backoffice JSON options and other fixes (#22885)
* Extension template: Configure BackOffice JSON options and replace IUser response with WhoAmIResponseModel

Sets the extension template's backoffice API to use the BackOffice named JsonOptions so the extension's serializer is insulated from consumer-level overrides.

The sample whoAmI endpoint previously returned IUser directly. IUser is a Umbraco.Core domain interface, not an API contract - it has no JSON polymorphism configuration and its nested interface properties (e.g. IReadOnlyUserGroup) are not designed to be serialized as part of an HTTP response. Once the BackOffice JsonOptions activated UmbracoJsonTypeInfoResolver for the extension's OpenAPI document, schema generation produced incomplete output (no type information on the Groups property).

Replaces the return type with a flat WhoAmIResponseModel exposing only the fields the dashboard UI consumes (name, email, groups). Domain interfaces should not be exposed directly on a controller - always project into a dedicated response model.

* Extension template: Fully-qualify Cms.Core references and drop Umbraco.Extensions import

The composer and controller base referenced `Cms.Core.Constants...` in short form, which relied on namespace fallback from `Umbraco.Extension.Controllers` finding `Umbraco.Cms.Core`. When consumers instantiate the template with a non-Umbraco root namespace, that fallback breaks. References are now fully qualified as `Umbraco.Cms.Core.Constants...`.

Additionally, the `whoAmI` controller's `using Umbraco.Extensions;` was getting mangled by the template engine's token substitution of `Umbraco.Extension` into the consumer's name. Replaces `WhereNotNull()` with the BCL-only `OfType<string>()` so the controller no longer depends on the `Umbraco.Extensions` namespace.

* Extension template: Tighten whoAmI 204 guard in dashboard

The generated client returns a truthy empty data object (or null body) for a 204 response, so the previous `if (data)` check could pass and render `undefined` values in the notification. Checks `data?.email` instead - it's a required field on a real 200 response and absent in the 204 fallback.

* Extension template: Return 401 Unauthorized from whoAmI and simplify dashboard handling

When `BackOfficeSecurity.CurrentUser` is null, the sample `whoAmI` endpoint now returns `Unauthorized()` instead of `NoContent()`, matching the `GetCurrentUserController` pattern in the Management API. Drops the 204 ProducesResponseType so the OpenAPI spec only advertises 200 plus the framework-emitted 401.

The dashboard collapses its empty-data check into a single `error || !data` guard, moves the notification into the success branch, and regenerates the client to drop the now-unused 204 response.
2026-05-20 10:55:45 +02:00
af04872023 Content Editing: Fix save composition values on invariant content and save of default segment (closes #22800, #22865) (#22846)
* Fix edit of a variant property composed to an invariant document.

* Collapse multi-line guard comment to a single line per project policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add unit test coverage for invariant content with a culture-variant composition property.

Adds a third mock document/document-type pair representing an invariant
content type whose flattened property list contains a culture-variant
property (the runtime shape produced when a variant composition is applied
to an invariant content type) and a setPropertyValue test asserting the
value is stored as a culture/segment-invariant entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove null guard for segment variant documents, as null segment is the default segment.

* update mock data and tests to include real compositions

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-05-20 10:53:46 +02:00
8aaac65f83 Content Editing: Fix save composition values on invariant content and save of default segment (closes #22800, #22865) (#22846)
* Fix edit of a variant property composed to an invariant document.

* Collapse multi-line guard comment to a single line per project policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add unit test coverage for invariant content with a culture-variant composition property.

Adds a third mock document/document-type pair representing an invariant
content type whose flattened property list contains a culture-variant
property (the runtime shape produced when a variant composition is applied
to an invariant content type) and a setPropertyValue test asserting the
value is stored as a culture/segment-invariant entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove null guard for segment variant documents, as null segment is the default segment.

* update mock data and tests to include real compositions

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-05-20 10:52:09 +02:00
8d5826c61f Content Editing: Fix save composition values on invariant content and save of default segment (closes #22800, #22865) (#22846)
* Fix edit of a variant property composed to an invariant document.

* Collapse multi-line guard comment to a single line per project policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add unit test coverage for invariant content with a culture-variant composition property.

Adds a third mock document/document-type pair representing an invariant
content type whose flattened property list contains a culture-variant
property (the runtime shape produced when a variant composition is applied
to an invariant content type) and a setPropertyValue test asserting the
value is stored as a culture/segment-invariant entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove null guard for segment variant documents, as null segment is the default segment.

* update mock data and tests to include real compositions

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-05-20 10:43:02 +02:00
Lee KelleherandGitHub 5a73f63cfd feat(components): adds umb-entity-frame component + Storybook stories (#22844)
* feat(components): adds `umb-entity-frame` component + Storybook stories

* fix(components): address review feedback for `umb-entity-frame`

- Remove `pointer-events: auto` from `.tab` so the overlay is truly passive
  (was intercepting events above the parent and causing hover flicker when
  toggled via opacity).
- Replace `--uui-color-surface` tab text with `--uui-color-selected-contrast`
  (the proper paired contrast token) and expose
  `--umb-entity-frame-contrast-color` so consumers can override when supplying
  a non-default `--umb-entity-frame-color`. Fixes contrast in dark and
  high-contrast themes.
- Add `aria-hidden="true"` to `.tab`; the frame is purely decorative and the
  parent owns the real semantics.
- Add a unit test verifying slot content takes precedence over the `label`
  property.

* Removed `aria-hidden` from the label tab

As will need to be used with assistive technologies.
2026-05-20 08:39:49 +00:00
Andy Butland 09af8c044b Merge branch 'v17/dev' 2026-05-20 10:32:08 +02:00
e463cd3a0c Log Viewer: Defensively handle corrupt log files (closes #22820) (#22826)
* Defensively handle log file corruptions by amalgamating errors per file and reporting as warning.

* Addressed code review comments.

* Use local reference to Newtonsoft.Json so it's clear we are only using it for exception handling.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-05-20 07:22:54 +00:00
2901be793a Redirect URL Tracker: Remove ability to toggle from the UI (#22830)
* Remove the ability to enable or disable the redirect tracker from the UI.

* Addressed code review feedback.

* Update OpenApi.json.

* Regenerate backend SDK from updated OpenApi.json

* Update UI to use lozenge status indicator rather than an imperative action.

* Further UX tweak.

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-05-20 09:20:37 +02:00
Andy Butlandandmole f255fd7bff Bump version to 17.4.2. 2026-05-20 09:18:56 +02:00
7527de7c56 Migrations: Add auto upgrade coordination for load-balanced setups (#22815)
* Add auto upgrade coordination for load balanced setups

* Add tests

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix(infrastructure): move TryBecomeLeaderAsync inside try/catch in UnattendedUpgradeBackgroundService

Ensures DB exceptions thrown during migration coordination set BootFailed
rather than faulting the background service silently.

* Fix feedback

* Update src/Umbraco.Infrastructure/Install/MigrationCoordinator.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Recheck state

* fix(tests): update concurrent race test for post-claim DetermineRuntimeLevel check

The winner now calls DetermineRuntimeLevel() once from the post-claim check
and must see Upgrading; the loser polls twice before seeing Run. Transition
the mock on the second call instead of the first.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 09:18:56 +02:00
df12a3e467 Cache: Add scope-level cache version tier to reduce DB hits in bulk operations (#22563)
* Cache cacheversion on scope

* Add tests

* Cache: Use ConcurrentDictionary for the inner per-scope version map

The inner Dictionary<string, Guid> was not thread-safe. Replacing it
with ConcurrentDictionary<string, Guid> removes the hidden assumption
that the root scope is only accessed from a single thread at a time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update src/Umbraco.Core/Cache/IRepositoryCacheVersionAccessor.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Cache/RepositoryCacheVersionAccessorTests.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.Common/Cache/RepositoryCacheVersionAccessor.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Skips failing test so we can run nightly. THIS NEEDS TO BE REVERTED

* Revert "Skips failing test so we can run nightly. THIS NEEDS TO BE REVERTED"

This reverts commit c34d1736c336b3fcf7803b44e88f6018fa45c275.

* Only write version once pr. scope

* Add tests

* Remove unnececary locks

* Fix thread-safety: replace HashSet with ConcurrentHashSet and use GetOrAdd to eliminate TOCTOU races

* Add unit tests for RepositoryCacheVersionService

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andreas Zerbst <andr317c@live.dk>
2026-05-20 09:18:56 +02:00
Andy Butland 1dc47bf4a1 Merge branch 'release/18.0' 2026-05-19 18:44:42 +02:00
Andy Butland 5f26c16c8e Add synchronous fast path for retrieval of cached elements (aligning documents and media from the previous cherry-pick from 17). 2026-05-19 18:43:27 +02:00
Andy Butland 896f449343 Children/Descendants: improve traversal performance (closes #22646) (#22742)
* Add benchmark test for measuring improvements to children and descendant retrieval.

* Remove unnecessary sort from retrieval of children.

* Return the result of the filtered collection of children/decendants without materialising.

* Lazily build property wrappers when materializing IPublishedContent.

* Cache the ordered children list on NavigationNode.

* Cache descendants per parent on the navigation snapshot.

* Add synchronous fast path for retrieved of cached content.

* Additional unit tests.

* Add TODO to make UpdateSortOrder internal.

* Addressed code review feedback.

* Further unit tests.

* Future-proofed code comments.
2026-05-19 18:32:09 +02:00
Andy Butland 0b86312f52 Children/Descendants: improve traversal performance (closes #22646) (#22742)
* Add benchmark test for measuring improvements to children and descendant retrieval.

* Remove unnecessary sort from retrieval of children.

* Return the result of the filtered collection of children/decendants without materialising.

* Lazily build property wrappers when materializing IPublishedContent.

* Cache the ordered children list on NavigationNode.

* Cache descendants per parent on the navigation snapshot.

* Add synchronous fast path for retrieved of cached content.

* Additional unit tests.

* Add TODO to make UpdateSortOrder internal.

* Addressed code review feedback.

* Further unit tests.

* Future-proofed code comments.
2026-05-19 18:01:12 +02:00
Andy ButlandandGitHub f4592111fa Children/Descendants: improve traversal performance (closes #22646) (#22742)
* Add benchmark test for measuring improvements to children and descendant retrieval.

* Remove unnecessary sort from retrieval of children.

* Return the result of the filtered collection of children/decendants without materialising.

* Lazily build property wrappers when materializing IPublishedContent.

* Cache the ordered children list on NavigationNode.

* Cache descendants per parent on the navigation snapshot.

* Add synchronous fast path for retrieved of cached content.

* Additional unit tests.

* Add TODO to make UpdateSortOrder internal.

* Addressed code review feedback.

* Further unit tests.

* Future-proofed code comments.
2026-05-19 18:00:34 +02:00
Andy Butland d6893dbf0b Merge branch 'v17/dev' 2026-05-19 17:59:45 +02:00
Niels LyngsøandAndy Butland c00e470d70 Slider: fix duplicated property editor settings properties (#22898)
* fix duplicate slider pe-settings properties

* remove comment

* avoid throws
2026-05-19 17:57:56 +02:00
Andy Butland 93ec661240 Output Caching: Correctly gate auto-registration of UseOutputCache() middleware (#22897)
Correct the gating of the call to UseOutputCache() to only proceed Umbraco managed caching via configuration is enabled, and not consider existing implementation specific registrations.
2026-05-19 17:57:48 +02:00
1c3e17740d Content Workspace: Load Data-Types based on Loaded Content Types (#22886)
* Load Data-Types based on Loaded Content Types

* Update Comment

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* mergeObservables approach

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-19 17:57:03 +02:00
Andy Butland 4c909d8ce8 Merge branch 'release/17.4.1' into release/17.5.0 2026-05-19 17:54:19 +02:00
Andy Butland 12c699d5bd Merge branch 'release/17.4.1' into v17/dev 2026-05-19 17:47:47 +02:00
Niels LyngsøandGitHub ba29b91301 Slider: fix duplicated property editor settings properties (#22898)
* fix duplicate slider pe-settings properties

* remove comment

* avoid throws
2026-05-19 14:19:34 +00:00
Andy ButlandandGitHub 336bffe4c4 Output Caching: Correctly gate auto-registration of UseOutputCache() middleware (#22897)
Correct the gating of the call to UseOutputCache() to only proceed Umbraco managed caching via configuration is enabled, and not consider existing implementation specific registrations.
2026-05-19 16:18:21 +02:00
426e516c61 Content Workspace: Load Data-Types based on Loaded Content Types (#22886)
* Load Data-Types based on Loaded Content Types

* Update Comment

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* mergeObservables approach

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-19 15:02:13 +02:00
Andy Butland c718a3ce12 Bump version to 17.4.1. 2026-05-19 15:01:44 +02:00
Jacob Overgaard 81c8afbd44 Merge remote-tracking branch 'origin/v17/dev' 2026-05-19 11:54:36 +02:00
Jacob Overgaard f352a2e90e Docs: clarify DefaultUILanguage vs fallback culture in package-development
Adds a 'Default UI language vs fallback culture' subsection so package
authors don't conflate the active UI locale (en-US by default) with the
fallback dictionary culture (en). A third-party language pack overriding
canonical keys must declare 'culture: en-US' on a default install,
otherwise the registry filters it out — the keys come from en.ts but
the override extension's culture has to match the active locale.

Surfaced by a tester report after PR #22743 merged the login screen's
localization into the backoffice client: the registry was forcing 'en'
active at boot (fixed in PR #22822) which masked the distinction, and
the docs didn't spell it out either.
2026-05-19 11:03:45 +02:00
Jacob Overgaard 259b6787a5 Localization: Honor DefaultUILanguage on initial load (closes #22808) (#22822)
* Localization: Honor DefaultUILanguage on initial load (closes #22808)

Closes #22808.

Previously, the configured DefaultUILanguage was silently overridden to
'en' at startup because the UmbLocalizationRegistry constructor called
loadLanguage(UMB_DEFAULT_LOCALIZATION_CULTURE) unconditionally. The
configured locale rendered into <html lang="..."> by Razor never had a
chance to flow through to the active language.

Changes:

- localization.registry.ts: stop forcing the active language to 'en'
  in the constructor. Initial state is canonicalised from
  document.documentElement.lang, falling back to 'en' for empty or
  malformed input. The extension filter now always includes the
  default culture alongside the active locale so 'en' translations
  remain available as a key-level fallback regardless of which
  language is active. A synchronous tap mirrors the active locale to
  document.lang and the manager when the state changes, so a fresh
  element rendered between loadLanguage() and the async translation
  load picks up the right language immediately.

- localization.manager.ts: drop the MutationObserver on
  document.documentElement and rely on the registry as the single
  channel for language changes. setActiveLanguage accepts a `silent`
  option so the synchronous tap can update fields without firing a
  consumer notification (translations may still be loading). A new
  notifyLanguageChanged() method is fired by the registry once
  translations are in place.

- app.element.ts: subscribe to umbLocalizationRegistry.currentLanguage
  in connectedCallback and mirror it onto the host element's lang
  attribute, so myApp.lang reflects the source of truth rather than a
  stale snapshot of <html lang>.

- auth.element.ts (login app): same lang subscription, plus after the
  slim backoffice controller registers extensions, prefer the
  visitor's navigator.language if a matching localization extension
  exists (falls through baseName -> language -> en automatically).

Tests: new initialization tests for the registry, manager
setActiveLanguage tests, and the controller tests refactored to use
the new explicit setActiveLanguage API instead of writing directly to
document.documentElement.lang.

* Login: Only override DefaultUILanguage with navigator.language when default has no translation

If the admin sets DefaultUILanguage to a language we have a translation for,
respect that choice over the visitor's browser language. Falling back to
navigator.language only when the configured default isn't available avoids
silently ignoring the admin's explicit setting (e.g., DefaultUILanguage='da-DK'
on a site whose visitor's browser is 'en-GB' should still show Danish).

* Simplify: split setActiveLanguage from notifyLanguageChanged

Drop the silent option in favor of two intent-revealing methods:
setActiveLanguage updates the active language and direction without
side-effects; notifyLanguageChanged tells all connected controllers
to re-render against the current state. Callers compose them based
on what they need (the registry's pipeline updates language sync
then flushes notifications after async translation load).

Also extracts baseLocaleOf() helper, simplifies the navigator.language
match logic in the login app's #applyPreferredLanguage, and removes
narration-style comments in the new code.

* Restore deprecated UmbLocalizationManager.updateAll for backward compat

The old MutationObserver-driven updateAll() field was technically part
of the manager's public surface. Restore it as a deprecated alias that
reads document.lang/dir and forwards to setActiveLanguage + notifyLanguageChanged,
with a runtime UmbDeprecation warning pointing consumers at the new API.

* Fix deprecation removal version to v20 + correct baseLocaleOf JSDoc

Per the deprecation policy in CLAUDE.md (current major + 2): a method
deprecated in v18 must remain through v19 before removal, so the
earliest removal is v20, not v19.

Also corrects the baseLocaleOf JSDoc — Intl.Locale.baseName can include
script subtags (e.g. 'zh-Hant-TW'), not just language and region.

* Scope the active language to the host element, drop navigator.language

- Razor now sets `lang` on `<umb-app>` and `<umb-auth>` from
  DefaultUILanguage. The element passes its lang through on connect, so
  the host owns its own scope — future multi-backoffice scenarios (e.g.
  signing into two Umbraco Cloud sites in the same document) get their
  own language without fighting over a global `<html lang>`.

- The registry no longer reads or writes `document.documentElement.lang`.
  Host elements drive it via `loadLanguage()`; `<html lang>` stays as
  whatever Razor rendered.

- Removed the navigator.language preference detection in the login app.
  Not in scope for the bug fix and adds behavior the admin can't opt out
  of. The existing current-user-locale flow already handles per-user
  preference after login.

- Tests updated to assert on `umbLocalizationManager.documentLanguage`
  instead of `document.documentElement.lang`.

* Set <html lang="en"> to match the static (noscript) text in the templates

The page's `<html lang>` should describe the language of the document's
own innate content. Both Index.cshtml files only contain English static
text (the noscript fallback), so the page-level lang is now "en".

The dynamic UI inside <umb-app> / <umb-auth> carries its own `lang`
attribute (from DefaultUILanguage), which overrides for that subtree —
correct per the HTML spec for language inheritance.

* Drop deprecated UmbLocalizationManager.updateAll

It was public as an artifact of being an arrow function so it could be
passed to a MutationObserver without binding — not because it was
intended as part of the public API. External usage is effectively
zero, and the new explicit setActiveLanguage + notifyLanguageChanged
covers anyone who did reach for it.

* Docs: document active-language-on-host pattern in package-development.md

After PR #22822, the active UI language is driven by the shell elements
(<umb-app>, <umb-auth>) via their own lang attribute, not by <html lang>.
Document that so future contributors don't reach for the global.

* Collapse setActiveLanguage + notifyLanguageChanged into one method

The silent-write path is just `manager.documentLanguage = ...` — no new
method needed; the field is already public and was always writable. The
notify path keeps setActiveLanguage, which now both sets and notifies.

Net: one new public method on the manager instead of two.

* Inline the active-language write in the registry, drop setActiveLanguage

The previous version added setActiveLanguage on the manager as
a 'cleaner API' than direct field writes. But the manager's fields
(documentLanguage, documentDirection, connectedControllers) have
always been public, the registry is the only caller, and the wrapper
was just more public surface to maintain through the eventual
manager/registry collapse.

Net: -70 lines across the test file, no new public methods on the
manager, the registry pipeline writes the fields and iterates the
controllers directly where it would have called setActiveLanguage.

* Document that documentLanguage/Direction are read-only for consumers

Note in JSDoc that the only supported way to change the active language
is umbLocalizationRegistry.loadLanguage(). The fields stay writable for
the registry pipeline (cross-module internal); the comment is here so
the next contributor doesn't reach for them as a shortcut and end up
with the manager state out of sync with what's actually loaded.
2026-05-19 10:57:45 +02:00
Jacob Overgaard 1637d9b158 Merge branch 'release/17.5.0' into v17/dev 2026-05-19 10:55:58 +02:00
Jacob Overgaard 7737cd3d40 Localization: Honor DefaultUILanguage on initial load (closes #22808) (#22822)
* Localization: Honor DefaultUILanguage on initial load (closes #22808)

Closes #22808.

Previously, the configured DefaultUILanguage was silently overridden to
'en' at startup because the UmbLocalizationRegistry constructor called
loadLanguage(UMB_DEFAULT_LOCALIZATION_CULTURE) unconditionally. The
configured locale rendered into <html lang="..."> by Razor never had a
chance to flow through to the active language.

Changes:

- localization.registry.ts: stop forcing the active language to 'en'
  in the constructor. Initial state is canonicalised from
  document.documentElement.lang, falling back to 'en' for empty or
  malformed input. The extension filter now always includes the
  default culture alongside the active locale so 'en' translations
  remain available as a key-level fallback regardless of which
  language is active. A synchronous tap mirrors the active locale to
  document.lang and the manager when the state changes, so a fresh
  element rendered between loadLanguage() and the async translation
  load picks up the right language immediately.

- localization.manager.ts: drop the MutationObserver on
  document.documentElement and rely on the registry as the single
  channel for language changes. setActiveLanguage accepts a `silent`
  option so the synchronous tap can update fields without firing a
  consumer notification (translations may still be loading). A new
  notifyLanguageChanged() method is fired by the registry once
  translations are in place.

- app.element.ts: subscribe to umbLocalizationRegistry.currentLanguage
  in connectedCallback and mirror it onto the host element's lang
  attribute, so myApp.lang reflects the source of truth rather than a
  stale snapshot of <html lang>.

- auth.element.ts (login app): same lang subscription, plus after the
  slim backoffice controller registers extensions, prefer the
  visitor's navigator.language if a matching localization extension
  exists (falls through baseName -> language -> en automatically).

Tests: new initialization tests for the registry, manager
setActiveLanguage tests, and the controller tests refactored to use
the new explicit setActiveLanguage API instead of writing directly to
document.documentElement.lang.

* Login: Only override DefaultUILanguage with navigator.language when default has no translation

If the admin sets DefaultUILanguage to a language we have a translation for,
respect that choice over the visitor's browser language. Falling back to
navigator.language only when the configured default isn't available avoids
silently ignoring the admin's explicit setting (e.g., DefaultUILanguage='da-DK'
on a site whose visitor's browser is 'en-GB' should still show Danish).

* Simplify: split setActiveLanguage from notifyLanguageChanged

Drop the silent option in favor of two intent-revealing methods:
setActiveLanguage updates the active language and direction without
side-effects; notifyLanguageChanged tells all connected controllers
to re-render against the current state. Callers compose them based
on what they need (the registry's pipeline updates language sync
then flushes notifications after async translation load).

Also extracts baseLocaleOf() helper, simplifies the navigator.language
match logic in the login app's #applyPreferredLanguage, and removes
narration-style comments in the new code.

* Restore deprecated UmbLocalizationManager.updateAll for backward compat

The old MutationObserver-driven updateAll() field was technically part
of the manager's public surface. Restore it as a deprecated alias that
reads document.lang/dir and forwards to setActiveLanguage + notifyLanguageChanged,
with a runtime UmbDeprecation warning pointing consumers at the new API.

* Fix deprecation removal version to v20 + correct baseLocaleOf JSDoc

Per the deprecation policy in CLAUDE.md (current major + 2): a method
deprecated in v18 must remain through v19 before removal, so the
earliest removal is v20, not v19.

Also corrects the baseLocaleOf JSDoc — Intl.Locale.baseName can include
script subtags (e.g. 'zh-Hant-TW'), not just language and region.

* Scope the active language to the host element, drop navigator.language

- Razor now sets `lang` on `<umb-app>` and `<umb-auth>` from
  DefaultUILanguage. The element passes its lang through on connect, so
  the host owns its own scope — future multi-backoffice scenarios (e.g.
  signing into two Umbraco Cloud sites in the same document) get their
  own language without fighting over a global `<html lang>`.

- The registry no longer reads or writes `document.documentElement.lang`.
  Host elements drive it via `loadLanguage()`; `<html lang>` stays as
  whatever Razor rendered.

- Removed the navigator.language preference detection in the login app.
  Not in scope for the bug fix and adds behavior the admin can't opt out
  of. The existing current-user-locale flow already handles per-user
  preference after login.

- Tests updated to assert on `umbLocalizationManager.documentLanguage`
  instead of `document.documentElement.lang`.

* Set <html lang="en"> to match the static (noscript) text in the templates

The page's `<html lang>` should describe the language of the document's
own innate content. Both Index.cshtml files only contain English static
text (the noscript fallback), so the page-level lang is now "en".

The dynamic UI inside <umb-app> / <umb-auth> carries its own `lang`
attribute (from DefaultUILanguage), which overrides for that subtree —
correct per the HTML spec for language inheritance.

* Drop deprecated UmbLocalizationManager.updateAll

It was public as an artifact of being an arrow function so it could be
passed to a MutationObserver without binding — not because it was
intended as part of the public API. External usage is effectively
zero, and the new explicit setActiveLanguage + notifyLanguageChanged
covers anyone who did reach for it.

* Docs: document active-language-on-host pattern in package-development.md

After PR #22822, the active UI language is driven by the shell elements
(<umb-app>, <umb-auth>) via their own lang attribute, not by <html lang>.
Document that so future contributors don't reach for the global.

* Collapse setActiveLanguage + notifyLanguageChanged into one method

The silent-write path is just `manager.documentLanguage = ...` — no new
method needed; the field is already public and was always writable. The
notify path keeps setActiveLanguage, which now both sets and notifies.

Net: one new public method on the manager instead of two.

* Inline the active-language write in the registry, drop setActiveLanguage

The previous version added setActiveLanguage on the manager as
a 'cleaner API' than direct field writes. But the manager's fields
(documentLanguage, documentDirection, connectedControllers) have
always been public, the registry is the only caller, and the wrapper
was just more public surface to maintain through the eventual
manager/registry collapse.

Net: -70 lines across the test file, no new public methods on the
manager, the registry pipeline writes the fields and iterates the
controllers directly where it would have called setActiveLanguage.

* Document that documentLanguage/Direction are read-only for consumers

Note in JSDoc that the only supported way to change the active language
is umbLocalizationRegistry.loadLanguage(). The fields stay writable for
the registry pipeline (cross-module internal); the comment is here so
the next contributor doesn't reach for them as a shortcut and end up
with the manager state out of sync with what's actually loaded.
2026-05-19 10:52:55 +02:00
Andy Butland beb9fcf4e2 Merge branch 'release/18.0' 2026-05-19 10:39:40 +02:00
Andy Butland 8dd3ab51f4 Updated failing unit test. 2026-05-19 10:39:09 +02:00
Jacob OvergaardandGitHub 23851c872f Localization: Honor DefaultUILanguage on initial load (closes #22808) (#22822)
* Localization: Honor DefaultUILanguage on initial load (closes #22808)

Closes #22808.

Previously, the configured DefaultUILanguage was silently overridden to
'en' at startup because the UmbLocalizationRegistry constructor called
loadLanguage(UMB_DEFAULT_LOCALIZATION_CULTURE) unconditionally. The
configured locale rendered into <html lang="..."> by Razor never had a
chance to flow through to the active language.

Changes:

- localization.registry.ts: stop forcing the active language to 'en'
  in the constructor. Initial state is canonicalised from
  document.documentElement.lang, falling back to 'en' for empty or
  malformed input. The extension filter now always includes the
  default culture alongside the active locale so 'en' translations
  remain available as a key-level fallback regardless of which
  language is active. A synchronous tap mirrors the active locale to
  document.lang and the manager when the state changes, so a fresh
  element rendered between loadLanguage() and the async translation
  load picks up the right language immediately.

- localization.manager.ts: drop the MutationObserver on
  document.documentElement and rely on the registry as the single
  channel for language changes. setActiveLanguage accepts a `silent`
  option so the synchronous tap can update fields without firing a
  consumer notification (translations may still be loading). A new
  notifyLanguageChanged() method is fired by the registry once
  translations are in place.

- app.element.ts: subscribe to umbLocalizationRegistry.currentLanguage
  in connectedCallback and mirror it onto the host element's lang
  attribute, so myApp.lang reflects the source of truth rather than a
  stale snapshot of <html lang>.

- auth.element.ts (login app): same lang subscription, plus after the
  slim backoffice controller registers extensions, prefer the
  visitor's navigator.language if a matching localization extension
  exists (falls through baseName -> language -> en automatically).

Tests: new initialization tests for the registry, manager
setActiveLanguage tests, and the controller tests refactored to use
the new explicit setActiveLanguage API instead of writing directly to
document.documentElement.lang.

* Login: Only override DefaultUILanguage with navigator.language when default has no translation

If the admin sets DefaultUILanguage to a language we have a translation for,
respect that choice over the visitor's browser language. Falling back to
navigator.language only when the configured default isn't available avoids
silently ignoring the admin's explicit setting (e.g., DefaultUILanguage='da-DK'
on a site whose visitor's browser is 'en-GB' should still show Danish).

* Simplify: split setActiveLanguage from notifyLanguageChanged

Drop the silent option in favor of two intent-revealing methods:
setActiveLanguage updates the active language and direction without
side-effects; notifyLanguageChanged tells all connected controllers
to re-render against the current state. Callers compose them based
on what they need (the registry's pipeline updates language sync
then flushes notifications after async translation load).

Also extracts baseLocaleOf() helper, simplifies the navigator.language
match logic in the login app's #applyPreferredLanguage, and removes
narration-style comments in the new code.

* Restore deprecated UmbLocalizationManager.updateAll for backward compat

The old MutationObserver-driven updateAll() field was technically part
of the manager's public surface. Restore it as a deprecated alias that
reads document.lang/dir and forwards to setActiveLanguage + notifyLanguageChanged,
with a runtime UmbDeprecation warning pointing consumers at the new API.

* Fix deprecation removal version to v20 + correct baseLocaleOf JSDoc

Per the deprecation policy in CLAUDE.md (current major + 2): a method
deprecated in v18 must remain through v19 before removal, so the
earliest removal is v20, not v19.

Also corrects the baseLocaleOf JSDoc — Intl.Locale.baseName can include
script subtags (e.g. 'zh-Hant-TW'), not just language and region.

* Scope the active language to the host element, drop navigator.language

- Razor now sets `lang` on `<umb-app>` and `<umb-auth>` from
  DefaultUILanguage. The element passes its lang through on connect, so
  the host owns its own scope — future multi-backoffice scenarios (e.g.
  signing into two Umbraco Cloud sites in the same document) get their
  own language without fighting over a global `<html lang>`.

- The registry no longer reads or writes `document.documentElement.lang`.
  Host elements drive it via `loadLanguage()`; `<html lang>` stays as
  whatever Razor rendered.

- Removed the navigator.language preference detection in the login app.
  Not in scope for the bug fix and adds behavior the admin can't opt out
  of. The existing current-user-locale flow already handles per-user
  preference after login.

- Tests updated to assert on `umbLocalizationManager.documentLanguage`
  instead of `document.documentElement.lang`.

* Set <html lang="en"> to match the static (noscript) text in the templates

The page's `<html lang>` should describe the language of the document's
own innate content. Both Index.cshtml files only contain English static
text (the noscript fallback), so the page-level lang is now "en".

The dynamic UI inside <umb-app> / <umb-auth> carries its own `lang`
attribute (from DefaultUILanguage), which overrides for that subtree —
correct per the HTML spec for language inheritance.

* Drop deprecated UmbLocalizationManager.updateAll

It was public as an artifact of being an arrow function so it could be
passed to a MutationObserver without binding — not because it was
intended as part of the public API. External usage is effectively
zero, and the new explicit setActiveLanguage + notifyLanguageChanged
covers anyone who did reach for it.

* Docs: document active-language-on-host pattern in package-development.md

After PR #22822, the active UI language is driven by the shell elements
(<umb-app>, <umb-auth>) via their own lang attribute, not by <html lang>.
Document that so future contributors don't reach for the global.

* Collapse setActiveLanguage + notifyLanguageChanged into one method

The silent-write path is just `manager.documentLanguage = ...` — no new
method needed; the field is already public and was always writable. The
notify path keeps setActiveLanguage, which now both sets and notifies.

Net: one new public method on the manager instead of two.

* Inline the active-language write in the registry, drop setActiveLanguage

The previous version added setActiveLanguage on the manager as
a 'cleaner API' than direct field writes. But the manager's fields
(documentLanguage, documentDirection, connectedControllers) have
always been public, the registry is the only caller, and the wrapper
was just more public surface to maintain through the eventual
manager/registry collapse.

Net: -70 lines across the test file, no new public methods on the
manager, the registry pipeline writes the fields and iterates the
controllers directly where it would have called setActiveLanguage.

* Document that documentLanguage/Direction are read-only for consumers

Note in JSDoc that the only supported way to change the active language
is umbLocalizationRegistry.loadLanguage(). The fields stay writable for
the registry pipeline (cross-module internal); the comment is here so
the next contributor doesn't reach for them as a shortcut and end up
with the manager state out of sync with what's actually loaded.
2026-05-19 09:21:03 +01:00
Andreas Lykke BorgandGitHub 7e4ef037b9 Issue template: Update version lookup instructions in bug report template (closes #22867) (#22881)
Update version lookup instructions in bug report template
2026-05-19 09:39:46 +02:00
Andy Butland 003656e21e Merge branch 'release/18.0' 2026-05-19 09:36:09 +02:00
432031e287 Elements: Fix UdiEntityTypeHelper.ToUmbracoObjectType() for Element entities (#22874)
* Elements: Fix UdiEntityTypeHelper.ToUmbracoObjectType() for Element entities

Adds the missing Element and ElementContainer cases so the conversion is
symmetric with FromUmbracoObjectType().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove UdiEntityTypeHelperTests

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:33:49 +02:00
Andy Butland 2b85dd5fd6 Merge branch 'v17/dev' 2026-05-19 09:17:23 +02:00
62eb772936 Blueprints: Fix UdiEntityTypeHelper.ToUmbracoObjectType() for document blueprint containers (#22875)
* Blueprints: Fix UdiEntityTypeHelper.ToUmbracoObjectType() for document blueprint containers

Adds the missing DocumentBlueprintContainer case so the conversion is
symmetric with FromUmbracoObjectType().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add missing case for MemberTypeContainer.

* Use reflection to ensure other future missed cases are surfaced without having to explicitly extend the tests.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-19 09:14:52 +02:00
139ac6ad72 Blueprints: Fix UdiEntityTypeHelper.ToUmbracoObjectType() for document blueprint containers (#22875)
* Blueprints: Fix UdiEntityTypeHelper.ToUmbracoObjectType() for document blueprint containers

Adds the missing DocumentBlueprintContainer case so the conversion is
symmetric with FromUmbracoObjectType().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add missing case for MemberTypeContainer.

* Use reflection to ensure other future missed cases are surfaced without having to explicitly extend the tests.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-19 09:13:52 +02:00
cd4521bd77 Blueprints: Fix UdiEntityTypeHelper.ToUmbracoObjectType() for document blueprint containers (#22875)
* Blueprints: Fix UdiEntityTypeHelper.ToUmbracoObjectType() for document blueprint containers

Adds the missing DocumentBlueprintContainer case so the conversion is
symmetric with FromUmbracoObjectType().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add missing case for MemberTypeContainer.

* Use reflection to ensure other future missed cases are surfaced without having to explicitly extend the tests.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-19 09:11:09 +02:00
cd1524f810 Elements: Fix GetUdi() extension methods for Element entities (#22873)
Adds the missing GetUdi() overloads for IElement so v18 Global Elements
produce their umb://element/{key} identifier through the same extension
surface used for documents, media and members.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 15:36:27 +02:00
80e2764eda Migrations: Add auto upgrade coordination for load-balanced setups (#22815)
* Add auto upgrade coordination for load balanced setups

* Add tests

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix(infrastructure): move TryBecomeLeaderAsync inside try/catch in UnattendedUpgradeBackgroundService

Ensures DB exceptions thrown during migration coordination set BootFailed
rather than faulting the background service silently.

* Fix feedback

* Update src/Umbraco.Infrastructure/Install/MigrationCoordinator.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Recheck state

* fix(tests): update concurrent race test for post-claim DetermineRuntimeLevel check

The winner now calls DetermineRuntimeLevel() once from the post-claim check
and must see Upgrading; the loser polls twice before seeing Run. Transition
the mock on the second call instead of the first.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 12:06:34 +02:00
d9bb17de2a Relation Type: Migrate custom table collection view to generic table (#22837)
* migrate relation type table collection view to table kind

* update page locator

* Request relations when workspace unique is set

* fix types

* split models

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Use constant for relation type collection alias + remove redundant fields

* Add observer keys in relation-type workspace view

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-15 08:26:42 +00:00
72fdf281fd Backoffice: Provide entity context via UMB_ENTITY_CONTEXT in menu components (#22835)
* Use UmbEntityContext for entity actions

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-15 09:26:07 +02:00
Andy ButlandandGitHub b24c9ba8ac Log Viewer: Updated the saved log viewer searches for new installs to reference Umbraco.Cms instead of Umbraco.Core. (#22843)
* Updated the saved log viewer searches for new installs to reference Umbraco.Cms instead of Umbraco.Core.

* Update mock and default data too.
2026-05-15 08:29:09 +09:00
2377e9a555 Cache: Add scope-level cache version tier to reduce DB hits in bulk operations (#22563)
* Cache cacheversion on scope

* Add tests

* Cache: Use ConcurrentDictionary for the inner per-scope version map

The inner Dictionary<string, Guid> was not thread-safe. Replacing it
with ConcurrentDictionary<string, Guid> removes the hidden assumption
that the root scope is only accessed from a single thread at a time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update src/Umbraco.Core/Cache/IRepositoryCacheVersionAccessor.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Cache/RepositoryCacheVersionAccessorTests.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.Common/Cache/RepositoryCacheVersionAccessor.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Skips failing test so we can run nightly. THIS NEEDS TO BE REVERTED

* Revert "Skips failing test so we can run nightly. THIS NEEDS TO BE REVERTED"

This reverts commit c34d1736c336b3fcf7803b44e88f6018fa45c275.

* Only write version once pr. scope

* Add tests

* Remove unnececary locks

* Fix thread-safety: replace HashSet with ConcurrentHashSet and use GetOrAdd to eliminate TOCTOU races

* Add unit tests for RepositoryCacheVersionService

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andreas Zerbst <andr317c@live.dk>
2026-05-15 08:28:06 +09:00
Andy Butland f964a18b5b Merge branch 'release/17.5.0' of https://github.com/umbraco/Umbraco-CMS into release/17.5.0 2026-05-14 19:10:30 +02:00
Lee KelleherandAndy Butland 2369f00544 Mocks: Add missing signalR property to mock server configuration response (#22849)
Mocks: Add missing signalR property to mock server configuration response

The GetServerConfigurationResponse type was updated in #22700 to require
a signalR.skipNegotiation property, but the MSW mock handler was not
updated to match, causing a tsc compilation error.
2026-05-14 19:08:11 +02:00
Lee KelleherandGitHub 0f438c551c Mocks: Add missing signalR property to mock server configuration response (#22849)
Mocks: Add missing signalR property to mock server configuration response

The GetServerConfigurationResponse type was updated in #22700 to require
a signalR.skipNegotiation property, but the MSW mock handler was not
updated to match, causing a tsc compilation error.
2026-05-14 17:05:55 +00:00
Sebastiaan Janssen d822518dd3 Core: Preserve path case in ShadowFileSystem (#22838)
* Core: Preserve path case in ShadowFileSystem

ShadowFileSystem stored staged files at their original case via _sfs.AddFile
but tracked them under a lowercased key (NormPath calling ToLowerInvariant).
On Complete(), Inner.AddFile(kvp.Key, _sfs.GetFullPath(kvp.Key)) reconstructed
the staged file's path from the lowercased key, so on case-sensitive file
systems (Linux) File.Move failed with FileNotFoundException whenever a path
contained any uppercase character.

Drop the ToLowerInvariant from NormPath and switch the tracking dictionary
to StringComparer.OrdinalIgnoreCase. Lookups remain case-insensitive
(matching Windows semantics) while the stored key now matches what was
written to disk. IsChild/IsDescendant updated to OrdinalIgnoreCase
StartsWith for consistency.

Added regression test reproducing the original FileNotFoundException with
Views/PageNotFound.cshtml.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Rename regression test to follow Can_ naming convention

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Track canonical staged path per shadow node

The case-insensitive node dictionary preserved only the first inserted
key, so re-staging a logical path with a different case (e.g. AddFile
"Views/Foo.cshtml" then "views/foo.cshtml") wrote a phantom second file
to _sfs on Linux while Complete still resolved the original key — leaving
orphaned shadow files and committing stale content.

Track the original-case staged path on each ShadowNode and route all
_sfs operations (AddFile, OpenFile, GetFullPath, GetLastModified,
GetCreated, GetSize, MoveFile, Complete) through that canonical path.
Inner.AddFile on commit still uses the stored dictionary key, so the
destination case in the inner file system is unchanged.

Expanded the regression test to also exercise OpenFile, GetSize and
AddFile against a different-cased path, and to assert that the staged
file is written exactly once.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Make ShadowNode.CanonicalPath non-nullable

Every node now carries the original-case path it tracks, set at construction.
This removes the defensive 'sf.CanonicalPath ?? path' fallbacks at the read
sites (OpenFile, GetFullPath, GetLastModified, GetCreated, GetSize, Complete)
which were unreachable but noise.

The GetCanonicalPath helper is gone; AddFile and MoveFile now use the existing
node variable inline ('sf?.CanonicalPath ?? path' — node can legitimately be
null when staging a path for the first time).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address Copilot review: normalize delete key, cross-platform test

DeleteDirectory(recursive=false) stored the deletion marker under the
caller-supplied path (which can contain backslashes) instead of the
normalized key, so a follow-up NormPath-based lookup could miss the
deletion and IsChild scans could become inconsistent. Use normPath.

The shadow-second-file assertion in the regression test used
File.Exists on a different-cased path; that returns true on
case-insensitive file systems (Windows / default macOS) regardless of
the actual stored case, so the assertion was platform-dependent.
Replaced it with a directory-count check that's cross-platform.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add cross-platform regression test so any reversion would be caught on a non-case sensitive file system.

* Cleaned up warnings, obsoletions and comments in the existing tests.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
(cherry picked from commit abfa8cb144)
2026-05-14 10:42:20 +02:00
Sebastiaan Janssen 136c494d82 Core: Preserve path case in ShadowFileSystem (#22838)
* Core: Preserve path case in ShadowFileSystem

ShadowFileSystem stored staged files at their original case via _sfs.AddFile
but tracked them under a lowercased key (NormPath calling ToLowerInvariant).
On Complete(), Inner.AddFile(kvp.Key, _sfs.GetFullPath(kvp.Key)) reconstructed
the staged file's path from the lowercased key, so on case-sensitive file
systems (Linux) File.Move failed with FileNotFoundException whenever a path
contained any uppercase character.

Drop the ToLowerInvariant from NormPath and switch the tracking dictionary
to StringComparer.OrdinalIgnoreCase. Lookups remain case-insensitive
(matching Windows semantics) while the stored key now matches what was
written to disk. IsChild/IsDescendant updated to OrdinalIgnoreCase
StartsWith for consistency.

Added regression test reproducing the original FileNotFoundException with
Views/PageNotFound.cshtml.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Rename regression test to follow Can_ naming convention

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Track canonical staged path per shadow node

The case-insensitive node dictionary preserved only the first inserted
key, so re-staging a logical path with a different case (e.g. AddFile
"Views/Foo.cshtml" then "views/foo.cshtml") wrote a phantom second file
to _sfs on Linux while Complete still resolved the original key — leaving
orphaned shadow files and committing stale content.

Track the original-case staged path on each ShadowNode and route all
_sfs operations (AddFile, OpenFile, GetFullPath, GetLastModified,
GetCreated, GetSize, MoveFile, Complete) through that canonical path.
Inner.AddFile on commit still uses the stored dictionary key, so the
destination case in the inner file system is unchanged.

Expanded the regression test to also exercise OpenFile, GetSize and
AddFile against a different-cased path, and to assert that the staged
file is written exactly once.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Make ShadowNode.CanonicalPath non-nullable

Every node now carries the original-case path it tracks, set at construction.
This removes the defensive 'sf.CanonicalPath ?? path' fallbacks at the read
sites (OpenFile, GetFullPath, GetLastModified, GetCreated, GetSize, Complete)
which were unreachable but noise.

The GetCanonicalPath helper is gone; AddFile and MoveFile now use the existing
node variable inline ('sf?.CanonicalPath ?? path' — node can legitimately be
null when staging a path for the first time).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address Copilot review: normalize delete key, cross-platform test

DeleteDirectory(recursive=false) stored the deletion marker under the
caller-supplied path (which can contain backslashes) instead of the
normalized key, so a follow-up NormPath-based lookup could miss the
deletion and IsChild scans could become inconsistent. Use normPath.

The shadow-second-file assertion in the regression test used
File.Exists on a different-cased path; that returns true on
case-insensitive file systems (Windows / default macOS) regardless of
the actual stored case, so the assertion was platform-dependent.
Replaced it with a directory-count check that's cross-platform.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add cross-platform regression test so any reversion would be caught on a non-case sensitive file system.

* Cleaned up warnings, obsoletions and comments in the existing tests.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
(cherry picked from commit abfa8cb144)
2026-05-14 10:42:07 +02:00
abfa8cb144 Core: Preserve path case in ShadowFileSystem (#22838)
* Core: Preserve path case in ShadowFileSystem

ShadowFileSystem stored staged files at their original case via _sfs.AddFile
but tracked them under a lowercased key (NormPath calling ToLowerInvariant).
On Complete(), Inner.AddFile(kvp.Key, _sfs.GetFullPath(kvp.Key)) reconstructed
the staged file's path from the lowercased key, so on case-sensitive file
systems (Linux) File.Move failed with FileNotFoundException whenever a path
contained any uppercase character.

Drop the ToLowerInvariant from NormPath and switch the tracking dictionary
to StringComparer.OrdinalIgnoreCase. Lookups remain case-insensitive
(matching Windows semantics) while the stored key now matches what was
written to disk. IsChild/IsDescendant updated to OrdinalIgnoreCase
StartsWith for consistency.

Added regression test reproducing the original FileNotFoundException with
Views/PageNotFound.cshtml.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Rename regression test to follow Can_ naming convention

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Track canonical staged path per shadow node

The case-insensitive node dictionary preserved only the first inserted
key, so re-staging a logical path with a different case (e.g. AddFile
"Views/Foo.cshtml" then "views/foo.cshtml") wrote a phantom second file
to _sfs on Linux while Complete still resolved the original key — leaving
orphaned shadow files and committing stale content.

Track the original-case staged path on each ShadowNode and route all
_sfs operations (AddFile, OpenFile, GetFullPath, GetLastModified,
GetCreated, GetSize, MoveFile, Complete) through that canonical path.
Inner.AddFile on commit still uses the stored dictionary key, so the
destination case in the inner file system is unchanged.

Expanded the regression test to also exercise OpenFile, GetSize and
AddFile against a different-cased path, and to assert that the staged
file is written exactly once.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Make ShadowNode.CanonicalPath non-nullable

Every node now carries the original-case path it tracks, set at construction.
This removes the defensive 'sf.CanonicalPath ?? path' fallbacks at the read
sites (OpenFile, GetFullPath, GetLastModified, GetCreated, GetSize, Complete)
which were unreachable but noise.

The GetCanonicalPath helper is gone; AddFile and MoveFile now use the existing
node variable inline ('sf?.CanonicalPath ?? path' — node can legitimately be
null when staging a path for the first time).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address Copilot review: normalize delete key, cross-platform test

DeleteDirectory(recursive=false) stored the deletion marker under the
caller-supplied path (which can contain backslashes) instead of the
normalized key, so a follow-up NormPath-based lookup could miss the
deletion and IsChild scans could become inconsistent. Use normPath.

The shadow-second-file assertion in the regression test used
File.Exists on a different-cased path; that returns true on
case-insensitive file systems (Windows / default macOS) regardless of
the actual stored case, so the assertion was platform-dependent.
Replaced it with a directory-count check that's cross-platform.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add cross-platform regression test so any reversion would be caught on a non-case sensitive file system.

* Cleaned up warnings, obsoletions and comments in the existing tests.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-14 10:36:47 +02:00
Andy Butland 21ab470d88 Merge branch 'release/17.4.0' into release/17.5.0 2026-05-14 08:31:39 +02:00
Andy Butland 5dd8378c57 Merge branch 'release/17.4.0' into v17/dev 2026-05-14 08:30:01 +02:00
Andy Butland 60655da1c2 Bump version to 18.0.0-beta3. 2026-05-14 08:14:25 +02:00
Andy Butland 4b82828a23 Merge branch 'release/18.0' 2026-05-14 08:11:39 +02:00
Jacob OvergaardandGitHub 756510d9e7 Backoffice: Fix typedoc UI API docs generation (#22836)
The Generate API Docs CI step (npm run generate:ui-api-docs) has been
failing with 3284 TypeScript errors since the TS 5.9.3 -> 6.0.3 bump in
PR #22591. TS 6 stopped auto-loading @types/* under moduleResolution:
"bundler", so every .test.ts file in the program fails to find describe,
it, beforeEach, etc., and typedoc aborts before emitting anything.

Point typedoc at a dedicated tsconfig.typedoc.json that narrows include
to src/**/*.ts + index.ts and excludes *.test.ts and *.stories.ts.
Entry points come from package.json exports and all live under src/, so
the docs build no longer drags test files, stories, mocks, e2e specs,
or storybook stories through the TS program.

Verified locally: npm run generate:ui-api-docs exits 0 and writes
6533 files under src/Umbraco.Web.UI.Client/ui-api/.
2026-05-14 06:43:22 +02:00
Jacob OvergaardandAndy Butland 2954578386 Backoffice: Preserve prerelease tag when hoisting peer dependencies (#22841)
The publish cleanse step strips the prerelease suffix from hoisted dependency
ranges via `semver.minVersion(...).major/minor/patch`. For `^2.0.0-rc.1`
this produced `^2.0.0`, which no published `@umbraco-ui/uui` version
currently satisfies, breaking extension installs against
`@umbraco-cms/backoffice@18.0.0-beta1`+.

Use the full SemVer (including any prerelease) as the floor so
`^2.0.0-rc.1` stays satisfiable by the actual published rc.
2026-05-13 22:52:51 +02:00
Jacob OvergaardandGitHub 3e7c1fa8e4 Backoffice: Preserve prerelease tag when hoisting peer dependencies (#22841)
The publish cleanse step strips the prerelease suffix from hoisted dependency
ranges via `semver.minVersion(...).major/minor/patch`. For `^2.0.0-rc.1`
this produced `^2.0.0`, which no published `@umbraco-ui/uui` version
currently satisfies, breaking extension installs against
`@umbraco-cms/backoffice@18.0.0-beta1`+.

Use the full SemVer (including any prerelease) as the floor so
`^2.0.0-rc.1` stays satisfiable by the actual published rc.
2026-05-13 22:51:55 +02:00
Andy Butland 3aa87fec96 Bump version to 17.4.0. 2026-05-13 17:39:57 +02:00
Mads RasmussenandGitHub 8e7440580a User: Delete unused custom table collection view (#22839)
delete unused user table code
2026-05-13 17:36:03 +02:00
Mads RasmussenandGitHub 358d435948 Member Group: Migrate custom table collection view to generic table kind (#22833)
* Migrate member group custom table to use table kind

* Use data-mark collection view selector for member group view
2026-05-13 17:04:22 +02:00
Andreas Lykke BorgandGitHub dcf1595e74 Accessibility: Added missing labels to code block copy button and embedded media URL input (#22825)
* Added label to copy button

* Added label to url input in editor

* Changed term to url

* Removed unnecessary readonly #localize

* Added copied translation key
2026-05-13 14:17:29 +00:00
Andy Butland 7b579cd021 Merge branch 'v17/dev' 2026-05-13 15:45:47 +02:00
Ronald BarendseandAndy Butland 6fef118a8f SignalR: Mark ServerEventSender as a distributed cache notification handler (#22818)
* Mark ServerEventSender as distributed cache notification handler

* Batch and deduplicate notifications in ServerEventSender

* Introduce IDistributedCacheAsyncNotificationHandler<T> and use it in ServerEventSender

* Add ServerEventSender unit tests and address PR review feedback
2026-05-13 14:44:30 +02:00
Jacob Overgaard 1edd6ec0bc Merge branch 'release/18.0' 2026-05-13 13:44:17 +02:00
Laura Neto c4a3b95195 Bump version to 18.0.0-beta2 2026-05-13 13:16:59 +02:00
d2d0d6d2d8 System information: Adds __uuiVersions to sysinfo output (#22831)
* feat: adds `__uuiVersions` to system information output

* avoid printet the array of version by handle single or multiple versions

* feat: ensures type safety of global variable

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-05-13 12:07:17 +02:00
f245bc00d0 UI: UI Library adjustments for v18 (#22824)
* transfer style to uui v2

* accordingly interactive state for document-links

* overflow clip for border radius appearance

* link style

* fix block grid area configuration

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-13 10:04:18 +00:00
Jacob OvergaardandGitHub c385991ffb build(deps): bumps @umbraco-ui/uui from 2.0.0-alpha.1 to 2.0.0-rc.0 (#22827) 2026-05-13 09:59:46 +00:00
0add0f5b18 Backoffice: Preserve user-supplied property editor UI group names (closes #22189) (#22196)
* Preserve user-supplied property editor UI group names.

* Add support for localised property editor groups, and use localised values for all core property editors.

* Fixed check to look for '#' as the first character of the provided group name.

* danish translation

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-05-13 11:29:51 +02:00
Jacob Overgaard 14886a9425 build: updates acceptance test lockfile 2026-05-13 09:56:34 +02:00
Nhu DinhandGitHub 79aadd827a Build: Updated nightly E2E test pipeline schedule in v18 (#22802)
Update nightly e2e test pipeline
2026-05-13 06:33:02 +00:00
Ronald BarendseandAndy Butland 4921ab9257 SignalR: Mark ServerEventSender as a distributed cache notification handler (#22818)
* Mark ServerEventSender as distributed cache notification handler

* Batch and deduplicate notifications in ServerEventSender

* Introduce IDistributedCacheAsyncNotificationHandler<T> and use it in ServerEventSender

* Add ServerEventSender unit tests and address PR review feedback
2026-05-13 08:29:22 +02:00
Ronald BarendseandGitHub e07f188bd4 SignalR: Mark ServerEventSender as a distributed cache notification handler (#22818)
* Mark ServerEventSender as distributed cache notification handler

* Batch and deduplicate notifications in ServerEventSender

* Introduce IDistributedCacheAsyncNotificationHandler<T> and use it in ServerEventSender

* Add ServerEventSender unit tests and address PR review feedback
2026-05-13 08:26:50 +02:00
Nhu DinhandGitHub 4bb5864e20 E2E: QA Updated acceptance tests to match the recent changes (#22801)
* Updated locator for user group table

* Updated json builder for user groups permission due to element folder permission

* Updated api helper to match with element folder permission

* Updated tests and add comments for the failing tests
2026-05-13 12:15:43 +07:00
Ronald Barendseandleekelleher af03e1d30a User Permission: Re-export fallback condition config type and global augmentation (#22794)
(cherry picked from commit 55fec1dc2a)
2026-05-12 17:15:56 +01:00
Ronald Barendseandleekelleher 63bae5958a User Permission: Re-export fallback condition config type and global augmentation (#22794)
(cherry picked from commit 55fec1dc2a)
2026-05-12 17:15:28 +01:00
Ronald BarendseandGitHub 55fec1dc2a User Permission: Re-export fallback condition config type and global augmentation (#22794) 2026-05-12 17:14:48 +01:00
Andy Butlandandleekelleher 50727c4bb8 Sort Children: Show loading state on Sort button (closes #22651) (#22813)
* Add submit button state to sort dialog.

* Guard against re-entrant submit in sort-children-of modal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Set failed button state when sort-children-of submit throws.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit dfe93c5639)
2026-05-12 17:07:59 +01:00
Andy Butlandandleekelleher 35d726ad31 Sort Children: Show loading state on Sort button (closes #22651) (#22813)
* Add submit button state to sort dialog.

* Guard against re-entrant submit in sort-children-of modal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Set failed button state when sort-children-of submit throws.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit dfe93c5639)
2026-05-12 17:06:44 +01:00
dfe93c5639 Sort Children: Show loading state on Sort button (closes #22651) (#22813)
* Add submit button state to sort dialog.

* Guard against re-entrant submit in sort-children-of modal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Set failed button state when sort-children-of submit throws.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 17:04:03 +01:00
Andy ButlandandGitHub def5be0855 18.0-beta1: Recycle Bin: Fix empty action button in collection view (closes #22798) (#22811)
Fix empty action button in collection view.
2026-05-12 16:31:07 +01:00
Niels LyngsøandGitHub 0a3647e4f0 v18 login photo (#22814) 2026-05-12 16:04:48 +02:00
Kenn Jacobsen 3daf7275ff Content: Ensure correct variant change tracking when unpublishing variant content (#22799)
(cherry picked from commit 6766eb9411)
2026-05-12 13:30:04 +02:00
kjac 2a2252474f Merge remote-tracking branch 'origin/main' 2026-05-12 12:32:07 +02:00
Jacob Overgaard 9c15572a49 fix: reinstates ./element export 2026-05-12 12:13:39 +02:00
Jacob Overgaard 045db8d699 fix: reinstate ./library export 2026-05-12 12:13:05 +02:00
kjac ecd29d79ff Merge remote-tracking branch 'origin/main' 2026-05-12 11:56:45 +02:00
Jacob Overgaard 60104e2a0e chore: regenerates tsconfig.json 2026-05-12 11:02:23 +02:00
Jacob Overgaard 2d747c0b43 chore: set version back to 18.1.0 2026-05-12 10:43:05 +02:00
Nhu DinhandGitHub 22a7a9577b Build: Updated nightly E2E test pipeline schedule in v17 (#22803)
Updated nightly E2E test pipeline schedule
2026-05-12 15:36:27 +07:00
Kenn Jacobsen 6766eb9411 Content: Ensure correct variant change tracking when unpublishing variant content (#22799) 2026-05-12 10:21:41 +02:00
Jacob Overgaard c9c4704e1a fix: exports condition configs and fixes test imports 2026-05-12 10:12:46 +02:00
Jacob Overgaard 0b0fea04d9 chore: sets version in backoffice client and regen packagel ock 2026-05-12 10:08:01 +02:00
Kenn JacobsenandAndy Butland fc9ca861b0 Content: Ensure correct variant change tracking when unpublishing variant content (#22799)
* Ensure correct change tracking when unpublishing

* Update src/Umbraco.Core/Services/PublishStatus/PublishStatusService.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Add comment

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-12 10:01:20 +02:00
c784858b32 Content: Ensure correct variant change tracking when unpublishing variant content (#22799)
* Ensure correct change tracking when unpublishing

* Update src/Umbraco.Core/Services/PublishStatus/PublishStatusService.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Add comment

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-12 09:58:20 +02:00
Laura NetoandGitHub f007855696 Open API: Add fluent builder for registering custom backoffice OpenAPI documents (#22774)
* Add helper for registering custom backoffice OpenAPI documents

Bundles AddOpenApi, the [MapToApi]-aware ShouldInclude predicate, the
Umbraco schema reference ID convention, and AddOpenApiDocumentToUi
behind a single IUmbracoBuilder.AddBackOfficeOpenApiDocument call.
Authors pass documentName, an optional title (used both as Info.Title
and the UI dropdown label), and an optional configure callback that
runs last so it can override anything the helper sets. An optional
jsonOptionsName is forwarded to ReplaceOpenApiSchemaService for
documents that need schema-time JSON serialization aligned to a named
JsonOptions.

Schema reference ID logic moves out of ConfigureUmbracoOpenApiOptionsBase
into UmbracoSchemaIdGenerator.CreateSchemaReferenceId so both the new
helper and the base class share one source of truth. The extension
template's composer collapses to a single AddBackOfficeOpenApiDocument
call, with document Info.Version, backoffice security, and the operation
ID transformer staying in the configure callback.

* Refactor backoffice OpenAPI helper into a fluent builder

Replace the parameter-list AddBackOfficeOpenApiDocument helper with a
callback-based form that yields a BackOfficeOpenApiDocumentBuilder. The
builder owns its state and applies it to the IUmbracoBuilder once the
user callback returns, so authors don't need to remember a terminal
Build call. Extension methods can layer on (e.g.
WithBackOfficeAuthentication in Umbraco.Cms.Api.Management) without the
core helper carrying every opinion.

Defaults stay sensible: filtering by [MapToApi(documentName)], the
Umbraco schema reference IDs, and the tag/sort transformers that v17's
global Swashbuckle pipeline applied. UI dropdown registration is
opt-out via ExcludeFromUi rather than opt-in. JSON options for schema
generation are an opt-in via WithHttpJsonOptions (instance or factory),
described purely in terms of the schema effect.

Move UmbracoSchemaIdGenerator's CreateSchemaReferenceId wrapper out of
ConfigureUmbracoOpenApiOptionsBase so both the base config class and
the new builder share one source of truth, and update the
ContentTypeSchemaTransformer / unit test callsites accordingly. Refresh
the extension template to use the new shape.

* Rename WithHttpJsonOptions to WithJsonOptions

The Http qualifier was naming the .NET type rather than the intent.
The parameter type carries the disambiguation; the method name is now
intent-focused and the XML doc explains the use case (matching the
serialization conventions of the API endpoints the document describes).

* Add WithJsonOptions(string) overload for named HTTP JsonOptions

Convenience overload that accepts the registered name and resolves the
matching Microsoft.AspNetCore.Http.Json.JsonOptions via IOptionsMonitor.
Documents on all three WithJsonOptions overloads now explicitly name
the HTTP JsonOptions type so consumers know which framework type they
are configuring.

* Migrate Management API OpenAPI registration to AddBackOfficeOpenApiDocument

Replaces the AddUmbracoOpenApiDocument<ConfigureUmbracoManagementApiOpenApiOptions>
call with the new fluent builder. The custom config class becomes dead
code and is deleted; all per-document opinions (Info metadata, security
requirements, transformers, JSON options) move into the configuration
callback alongside the document registration.

Behavior preserved: same ShouldInclude (now via [MapToApi]-only since
all Management controllers carry the attribute through their base class),
same schema reference IDs, same operation IDs via UmbracoOperationIdTransformer,
same backoffice security requirements, same schema/operation transformers,
same named JSON options for schema generation.

* Cleanup unused usings

* Address PR review feedback on AddBackOfficeOpenApiDocument

Make UmbracoOperationIdTransformer part of the builder's defaults instead of
the Management API adding it explicitly, and expand the XML docs on
AddBackOfficeOpenApiDocument to spell out the defaults a caller opts into.

Add tests covering the new builder and its defaults:
- Unit tests for BackOfficeOpenApiDocumentBuilder defaults (CreateSchemaReferenceId,
  ShouldInclude, ConfigureOpenApiOptions composition, WithTitle/WithUiTitle UI
  dropdown handling, ExcludeFromUi).
- Integration tests that register sample controllers, fetch the generated OpenAPI
  document and verify the defaults end-to-end: Info.Title from WithTitle,
  MapToApi filtering, Umbraco operation-id and schema-id conventions (including
  the version-suffix branch), tag-by-group-name and tag-first path sorting.
- Integration tests for the three WithJsonOptions overloads (instance, factory,
  named) confirming the configured JsonOptions reach schema generation.

* Remove redundant operation-id override from extension template

UmbracoOperationIdTransformer is now part of the AddBackOfficeOpenApiDocument
defaults, so the template's custom action-name transformer would only overwrite
the work the default just did. Drop it, and consolidate the documentation
pointer to a single link.

* Narrow MimeTypesTransformer to JSON-equivalent variants and register it in AddBackOfficeOpenApiDocument

Filter only removes redundant JSON-equivalent MIME types (text/json,
application/*+json, text/plain) when application/json is present.
Non-JSON types like application/xml are preserved. Register the
transformer as a default in AddBackOfficeOpenApiDocument so custom
backoffice documents get the same treatment as Umbraco's own APIs.

* Register RequireNonNullablePropertiesSchemaTransformer in AddBackOfficeOpenApiDocument

* Apply review notes

- Drop RequireNonNullablePropertiesSchemaTransformer and MimeTypesTransformer
  from the Management API's ConfigureOpenApiOptions block — both are now
  defaults on the builder.
- Expand MimeTypesTransformer XML docs to reflect its broader role (it now
  applies to every backoffice document, not just the Management API) and
  correct the response-side inline comment.
- Move MimeTypesTransformerTests from the Delivery test folder/namespace to
  the Api.Common test folder/namespace, since the transformer is no longer
  Delivery-specific.
- Rename BackOfficeOpenApiDocumentExtensionTests to
  UmbracoBuilderOpenApiExtensionsTests so the test fixture name matches the
  concrete class under test.
2026-05-12 09:55:08 +02:00
Sven Geusensandmole 4286a361d8 Distributed background jobs: Improve gracefull shutdown behaviour (#22796)
* Dont fail silently on missing ambientscope

This makes it in line with other methods in the repo

* Pass on Cancellationtoken to the job to support gracefull job shutdown

(cherry picked from commit 5ae17ace6a)
2026-05-12 09:52:41 +02:00
Sven Geusensandmole 68194e1a27 Distributed background jobs: Improve gracefull shutdown behaviour (#22796)
* Dont fail silently on missing ambientscope

This makes it in line with other methods in the repo

* Pass on Cancellationtoken to the job to support gracefull job shutdown

(cherry picked from commit 5ae17ace6a)
2026-05-12 09:51:25 +02:00
mole 91313fff0e Merge remote-tracking branch 'refs/remotes/origin/v17/dev'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
#	tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PublishedContent/PublishedValueFallbackTests.cs
#	version.json
2026-05-12 09:50:50 +02:00
Sven GeusensandGitHub 5ae17ace6a Distributed background jobs: Improve gracefull shutdown behaviour (#22796)
* Dont fail silently on missing ambientscope

This makes it in line with other methods in the repo

* Pass on Cancellationtoken to the job to support gracefull job shutdown
2026-05-12 09:28:00 +02:00
Nhu DinhandGitHub 3dca735a38 E2E: QA Added acceptance tests for current user workspace (#22457)
* Updated acceptance tests for current user profile

* Updated locator for save button

* Reverted npm command
2026-05-11 14:59:03 +00:00
Andy Butlandandleekelleher 57b9a7ef80 Tiptap RTE: Ignore no-op transactions in onUpdate to prevent phantom dirty state (closes #22767) (#22781)
Ignore Tiptap no-op transactions in onUpdate to prevent phantom dirty state.

(cherry picked from commit cd476ab6ed)
2026-05-11 14:14:21 +01:00
Andy ButlandandGitHub cd476ab6ed Tiptap RTE: Ignore no-op transactions in onUpdate to prevent phantom dirty state (closes #22767) (#22781)
Ignore Tiptap no-op transactions in onUpdate to prevent phantom dirty state.
2026-05-11 14:13:21 +01:00
Andy ButlandandGitHub 65a45a4ac6 18.0-beta1: User Management: Invalidate cached element start nodes on user save and fix access summary display (closes #22770) (#22779)
* Users: Invalidate cached element start nodes on user save (closes #22770)

* Fix display of selected element folders under the user's access summary.
2026-05-11 12:40:05 +01:00
Andy ButlandandGitHub 38b6752d24 18.0-beta1: Elements: Show trashed folder ancestor names in breadcrumb (closes #22768) (#22780)
Fix breadcrumb for trashed element within a folder.
2026-05-11 12:23:43 +01:00
Jacob Overgaardandleekelleher 097b9c11f6 Login: Reuse backoffice localization (closes #20082) (#22743)
* Login: Reuse backoffice localization for canonical login_* keys (closes #56402)

The login screen no longer ships its own localization tree. The slim backoffice controller registers the backoffice's built-in localization manifests, so all login screen text resolves from the same dictionary the in-backoffice auth view uses. Translators override one place; both screens reflect it.

All consumers in the Login project moved from auth_* to login_*. The Login project's localization/ directory is removed entirely. The auth.* keys it used to ship (form labels, mfa, invite, password reset) now live under login.* in the backoffice's en/da/de/nb/nl/sv lang files. Other backoffice languages fall back to en for these keys, automatically extending the login screen's language coverage.

* Backoffice localization: drop server-only email keys, add login.setPasswordInstruction in en/da/nb/sv

bottomText, resetPasswordEmailCopySubject, resetPasswordEmailCopyFormat, mfaSecurityCodeSubject and mfaSecurityCodeBody are read only by the server's own localization layer — they were dead weight in every backoffice lang dictionary that carried them. Removed across 23 lang files.

login.setPasswordInstruction is rendered on the new-password screen via the now-canonical login_* namespace; it was missing from en (the fallback), da, nb and sv. Added there using the same translation tone as the existing de/nl entries.

* Login: Honour legacy auth_greeting* overrides with UmbDeprecation warning

Translation packages still shipping 'auth_greeting0..6' overrides keep working on both welcome screens (the standalone login page and the in-backoffice umb-auth-view): when an auth_* greeting is registered the consumer prefers it, otherwise the canonical login_* key is used. Each legacy key triggers a one-time UmbDeprecation warning pointing at the canonical name. Scheduled for removal in v20.

* Fix Prettier formatting and correct issue references in deprecation message

Addresses Copilot review feedback on PR #22743:

- Run Prettier on the 6 backoffice lang files I added keys to (en/da/de/nb/nl/sv); the new entries used double quotes which violated the repo's singleQuote: true config and would have failed the format check.
- Update the UmbDeprecation 'solution' link and the inline source comments from #56402 (an ADO work item id) to #20082 (the actual GitHub issue tracking this work).

* Drop stale login_2fa* and login_mfaSecurityCodeMessage from bs.ts and cy.ts

Surfaced by 'devops/localization/compare-languages.js': bs and cy were the only lang files shipping these keys, and they have no en counterpart. The login_2fa* set is leftover from before the codebase renamed 2fa → mfa in the login flow (the live keys are login_mfa*). login_mfaSecurityCodeMessage is server-side only, like the other email-template keys cleaned up in 53ad52702e0. None of these are referenced anywhere in src/. The user-facing user_2fa* keys (consumed by current-user-mfa modals) are unrelated and untouched.

* Drop dead login_2fa* and login_mfaSecurityCodeMessage from nl, hr, tr

Same pattern as 26bc6211d27 (bs/cy cleanup), surfaced by re-running devops/localization/compare-languages.js after the previous pass:

- nl had both legacy 'login_2fa*' AND the canonical 'login_mfa*' (added in commit 1) sitting side by side after the auth.* → login.* port. Six true duplicates dropped, login_mfa* kept.
- hr and tr shipped legacy 'login_2fa*' that have no en counterpart, no consumer in src/, and no mfa pair locally. Dropped to align with en (the source of truth — every other locale should match it).

- All three files also still carried 'login_mfaSecurityCodeMessage' from the same family of server-side email-template keys cleaned up in 53ad52702e0; removed too.

user_2fa* / member_2fa keys are unrelated and untouched (consumed by current-user-mfa modals).

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
(cherry picked from commit def18e440f)
2026-05-11 12:01:23 +01:00
Jacob Overgaardandleekelleher 30d7161399 Login: Consume sibling Umbraco.Web.UI.Client by source for v18 parity (#22591)
* Login: Consume sibling Umbraco.Web.UI.Client by source for v18 parity

The Login project previously depended on the published `@umbraco-cms/backoffice@^17.3.4` npm package for types, while at runtime the importmap served the in-repo v18 backoffice. The version mismatch forced `as any` workarounds and masked real API drift. Since v18 (with UUI 2.0) isn't on npm yet, switch Login to consume the sibling Client via a local `file:` dep so types and runtime align on v18.

Changes:
- Login `package.json`: `@umbraco-cms/backoffice` → `file:../Umbraco.Web.UI.Client`; added `pre{build,dev,watch}` hooks that run a guard script to fail fast when Client's `dist-cms/` is missing.
- Login `scripts/ensure-client-built.mjs`: new guard with a clear "build the Client first" message.
- Login `CLAUDE.md`: documents the contract and build ordering.
- StaticAssets `.csproj`: `BuildLogin` now depends on `BuildBackoffice` so MSBuild (and therefore the Azure pipeline) builds Client before Login automatically.
- Client `src/tsconfig.build.json`: `declaration: true` so `dist-cms/` ships `.d.ts`.
- Client `package.json`: new `build:types` step (`tsc --emitDeclarationOnly --incremental false && tsc-alias`) wired into `build:for:cms` after `build:workspaces`. Vite workspaces wipe their output dirs before rebuilding JS, stripping the tsc-emitted declarations; re-emitting after workspaces restores them. `tsc-alias` rewrites Client-internal path aliases (e.g. `@umbraco-cms/backoffice/external/lit`) to relative paths so sibling consumers can resolve them.
- `copy-to-cms.js`: filter `.d.ts` and `.tsbuildinfo` from the copy to `wwwroot/umbraco/backoffice` — they're only needed by sibling projects consuming `dist-cms` for types, not at runtime.
- `src/external/uui/vite.config.ts`: set `treeshake: false` so per-component `defineElement()` side-effect calls (used by UUI 2.0 for custom-element registration) are preserved in the bundle. Without this, `<uui-button>` etc. never register and the login screen renders empty controls.
- `src/external/uui/index.ts`: bare `import '@umbraco-ui/uui'` to make the side-effect intent explicit.
- Small v18-compat fixes for `Object.groupBy` (TS 8 types): removed stale `@ts-expect-error`, switched to `Object.entries` + `?? []` to satisfy the `Partial<Record>` return type.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address review feedback and fix CI

- Add `ignoreDeprecations: "6.0"` to `tsconfig.json` and the tsconfig generator to silence the TS 6.0 warning about the implicit baseUrl that TypeScript assigns when `paths` is declared. This was the CI `build` failure. The generator is also synced with the user's es2022 → es2024 bump.
- Drop the now-redundant `--declaration` flag from `build:for:npm` (tsconfig.build.json now has `declaration: true`, so the flag was duplicating intent).
- Align Login's `engines` with the Client's (`node >=24.13`, `npm >=11`) so `file:` install doesn't trip EBADENGINE.
- Guard script: hardcode the relative "../Umbraco.Web.UI.Client" path in the error message instead of interpolating the absolute path, which overflowed the ASCII box in CI logs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Login: update CLAUDE.md Node/npm versions to match engines

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* check-path-length: skip .d.ts/.tsbuildinfo and directory paths

The 120-char Windows MAX_PATH guard protects files that actually ship to
CMS installs. `.d.ts` and `.tsbuildinfo` live in `dist-cms/` for sibling
projects to consume as types and are filtered out by `copy-to-cms.js`
before reaching `wwwroot/umbraco/backoffice` — they never land on a
Windows CMS install. Directories on their own also don't trigger
MAX_PATH; only files within them do, and those are still checked.

Unblocks CI after enabling `declaration: true` in the Client build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* check-path-length: extract exceedsPathLimit helper (CodeScene)

Decomposes the complex conditional flagged by CodeScene into a named
predicate with a docstring, clarifying when a path is reported.

* Login: switch to generated tsconfig paths; revert dist-cms type machinery

PR #22591 originally aligned Login's TypeScript types with the in-repo v18
backoffice by emitting `.d.ts` into Client's `dist-cms/` and consuming it
via a `file:` dep. That layered six side-effects across the Client build
(declaration: true, build:types step, tsc-alias in postbuild, copy-to-cms
filter, check:paths skip, MSBuild ordering). Reviewers pushed back.

This rework moves the type contract from "ship .d.ts in dist-cms" to
"point Login's tsconfig paths at Client's TypeScript source" — Login's
runtime behaviour is unchanged (vite still externalises /^@umbraco-cms/,
host importmap still serves the JS), only the type-resolution mechanism
swaps.

What's reverted (back to the pre-PR shape):
- src/Umbraco.Web.UI.Client/src/tsconfig.build.json: declaration: false
- src/Umbraco.Web.UI.Client/package.json: drops `build:types` script,
  reverts `postbuild` to global-types only, drops `--declaration` from
  the tsc CLI in `build:for:cms` and restores it in `build:for:npm`
- src/Umbraco.Web.UI.Client/devops/build/copy-to-cms.js: simple cpSync
- src/Umbraco.Web.UI.Client/devops/build/check-path-length.js: original
- src/Umbraco.Web.UI.Client/tsconfig.json + devops/tsconfig/index.js:
  drops `ignoreDeprecations` (not needed once baseUrl is gone)
- src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj:
  `BuildLogin` no longer depends on `BuildBackoffice`

What's new on the Login side:
- src/Umbraco.Web.UI.Login/devops/tsconfig/index.js: generator that
  reads Client's `package.json` exports and emits a full `tsconfig.json`
  with `paths` mapping every `@umbraco-cms/backoffice/<sub>` to
  `../Umbraco.Web.UI.Client/src/.../index.ts`. Mirrors Client's existing
  generator pattern (DON'T EDIT header, JSON.stringify with tabs).
- src/Umbraco.Web.UI.Login/tsconfig.json: regenerated; standalone `tsc`
  works (no `--project` needed) and 140 path aliases resolve types
  directly from Client's source.
- src/Umbraco.Web.UI.Login/package.json: drops `@umbraco-cms/backoffice`
  npm dep entirely (file: was only nominal — types come via paths,
  runtime via importmap, transitives via Client's own `node_modules`
  which is `npm install`-ed by CI's backoffice-install.yml). Replaces
  the `ensure-client-built` guard with the generator on `pre*` hooks
  and adds `generate:tsconfig` for ad-hoc invocation.
- src/Umbraco.Web.UI.Login/CLAUDE.md: documents the new layered
  contract (paths/externalisation/importmap) and the install-Client-
  before-Login prerequisite.
- src/Umbraco.Web.UI.Login/scripts/ensure-client-built.mjs: deleted.

What stays from the original PR (independent fixes):
- src/Umbraco.Web.UI.Client/src/external/uui/{vite.config.ts,index.ts}:
  `treeshake: false` + bare side-effect import — keeps UUI 2.0
  per-component `defineElement` calls in the bundle so `<uui-button>`
  etc. actually register.
- Object.groupBy cleanups in 6 element files (TS 8 type narrowing).
- Client tsconfig generator: target/lib bumped to ES2024, `baseUrl`
  removed.

Verified locally:
- `cd Client && rm -rf dist-cms && cd ../Login && npx tsc` → clean
  (proves Login compiles without Client's dist-cms)
- `cd Client && npm run build:for:cms` → 0 emitted .d.ts (back to
  pre-PR shape), `check:paths` passes
- Login `npm run build` → 64 KB bundle (unchanged)
- Browser at https://localhost:44339/umbraco: UUI 2.0 components
  render, login with `test@umbraco.com`/`test123456` succeeds and
  redirects to /umbraco/section/content

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Login: address review — idempotent generator + correct MSBuild ordering

- StaticAssets.csproj: BuildLogin now depends on RestoreBackoffice (not
  BuildBackoffice — Login doesn't need dist-cms types). Login's tsc walks
  Client source via tsconfig path aliases and resolves transitive deps
  (lit, rxjs, …) from Client's node_modules. Without this dependency a
  fresh local `dotnet build` could run BuildLogin before Client is
  installed; CI was already safe via backoffice-install.yml's npm ci.

- devops/tsconfig/index.js: skip rewrite when content is unchanged. Pre-
  hooks ran the generator on every npm command and bumped tsconfig.json
  mtime even when nothing changed, which can invalidate caches and rattle
  watchers downstream. Read-then-compare-then-write makes the generator
  truly idempotent.

- devops/tsconfig/index.js: derive the alias prefix from
  `clientPkg.name` instead of hardcoding `@umbraco-cms/backoffice` so a
  package rename can't silently break paths.

azure-pipelines.yml needs no changes — backoffice-install.yml already
runs `npm ci` in Client before dotnet build kicks in MSBuild.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Login: postinstall + dev-mode Vite alias + theme CSS path

Audit cleanup pass on the rework:

- Login package.json: collapse predev/prebuild/prewatch into a single
  postinstall hook. The generator runs whenever npm install/ci runs
  (locally + in CI via RestoreLogin's npm i + the dotnet build chain).
  Removes the per-command "tsconfig.json already up to date" noise.

- Login vite.config.ts: in dev mode (`vite serve`), read `paths` from
  the generated tsconfig.json and apply them as `resolve.alias` so Vite
  can resolve `@umbraco-cms/backoffice/*` to Client source. Vite doesn't
  honor tsconfig `paths` natively — without this `npm run dev` failed
  with "Failed to resolve import @umbraco-cms/backoffice/utils ...".
  Build mode (`vite build`) still externalises the namespace via the
  unchanged rollupOptions.external regex; alias is dev-only.

- Login index.html: UUI 2.0 reorganised CSS — the old
  `@umbraco-ui/uui-css/dist/uui-css.css` path no longer exists. Point
  at `@umbraco-ui/uui/dist/themes/light.css` which is what Client now
  ships. Path is relative through Client's node_modules since Login no
  longer declares a UUI dep itself.

- Client input-entity-user-permission.element.ts: prettier flagged a
  multi-line .map() arrow that should be inline; collapse to one line.

- Login CLAUDE.md: document the postinstall-driven generator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Use Vite 8 native tsconfigPaths; drop helper plugin and trim comments

- Both vite.config.ts files use `resolve.tsconfigPaths: true` instead of the
  `vite-tsconfig-paths` plugin. Plugin and dep removed.
- Trim explanatory comments on csproj target, generator, UUI vite config and
  external/uui/index.ts to conclusions only.

* Login: tsconfig generator fails fast on unsupported exports shapes

Distinguish between the legitimate `.` self-reference (target === null) and
unexpected non-string targets (e.g., conditional exports objects). The latter
now throw with a clear message instead of being silently dropped from `paths`,
which would otherwise produce confusing 'Cannot find module' errors at tsc
time later.

* Login: allow Vite dev server to serve Client's UUI assets

The light.css imported from Client's node_modules pulls Lato fonts via
relative URL, which Vite refuses by default since they sit outside
Login's project root. Extend server.fs.allow to the parent directory
(both sibling projects).

* Client: regenerate tsconfig on postinstall

* Login: keep UUI registrations in dev mode

Vite 8's esbuild dep pre-bundle drops the per-component
`customElements.define()` side-effects in @umbraco-ui/uui (a known UUI
issue with Vite 8). Exclude UUI from optimizeDeps so it's served
unbundled in dev. Re-add the bare side-effect import in external/uui
so the entry module evaluates the chain. Production build is unaffected
(workspace's `treeshake: false` already preserves registrations).

Also document the new MSBuild Login targets in StaticAssets CLAUDE.md.

* Login: clarify why optimizeDeps.exclude is needed for UUI

Tested treeshake.moduleSideEffects: true in optimizeDeps.rollupOptions
on Vite 8 / Rolldown 1.0.0-rc.17 — registrations still get stripped.
Excluding the package from the pre-bundle is the only reliable workaround
until UUI's own Vite 8 upgrade lands. Comment captures the conclusion.

* Roll back Vite 8 → 7 in Client and Login

Vite 8.0.10 ships Rolldown 1.0.0-rc.17 which strips UUI 2.0
`customElements.define()` side-effects during dep pre-bundle, leaving
elements unregistered in dev mode. Rather than ship a v18 release tied
to a non-final Rolldown RC, revert the Vite bump and pick it up again
once Rolldown 1.0 final lands.

Changes:
- Client: vite ^8.0.10 → ^7.3.2; vite-plugin-static-copy ^4.1.0 → ^3.2.0;
  re-add vite-tsconfig-paths plugin; drop native `resolve.tsconfigPaths`.
- Login: vite ^8.0.10 → ^7.3.2; add vite-tsconfig-paths; configure plugin
  with `projects: ['./tsconfig.json', '../Umbraco.Web.UI.Client/tsconfig.json']`
  so it can resolve `@umbraco-cms/backoffice/*` imports inside Client
  source files (which would otherwise lack a discoverable tsconfig in
  Login's project tree). Drop `optimizeDeps.exclude` (no longer needed
  without Rolldown). Keep `server.fs.allow` for the cross-project font.

TypeScript 6 + ES2024 + tsconfig path generator + Login architectural
pivot all stay — those are independent of the Vite version.

Verified:
- Production https://localhost:44339/umbraco — login works
- Login dev http://localhost:5191/ — UUI registers, all custom elements defined
- Client dev http://localhost:5192/ — page loads, navigates to /section/content

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address Copilot review

- vite.config.ts (Login): narrow server.fs.allow from the parent dir to
  Login + Client only, reducing the dev server's read scope.
- external/uui/vite.config.ts (Client): replace blanket `treeshake: false`
  with `moduleSideEffects: (id) => id.includes('@umbraco-ui/uui')` so
  Rollup keeps UUI's per-component registration calls but tree-shakes the
  rest. Bundle stays at 516 KB / 96 registered tags.

* fix merge overwrites

* update package lock

* fix: do not autogenerate tsconfig on postinstall

* removes postinstall script

* chore: generates tsconfig

* chore: update lockfile

* docs: updates claude.md

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
(cherry picked from commit 8a73d713cd)
2026-05-11 12:01:13 +01:00
def18e440f Login: Reuse backoffice localization (closes #20082) (#22743)
* Login: Reuse backoffice localization for canonical login_* keys (closes #56402)

The login screen no longer ships its own localization tree. The slim backoffice controller registers the backoffice's built-in localization manifests, so all login screen text resolves from the same dictionary the in-backoffice auth view uses. Translators override one place; both screens reflect it.

All consumers in the Login project moved from auth_* to login_*. The Login project's localization/ directory is removed entirely. The auth.* keys it used to ship (form labels, mfa, invite, password reset) now live under login.* in the backoffice's en/da/de/nb/nl/sv lang files. Other backoffice languages fall back to en for these keys, automatically extending the login screen's language coverage.

* Backoffice localization: drop server-only email keys, add login.setPasswordInstruction in en/da/nb/sv

bottomText, resetPasswordEmailCopySubject, resetPasswordEmailCopyFormat, mfaSecurityCodeSubject and mfaSecurityCodeBody are read only by the server's own localization layer — they were dead weight in every backoffice lang dictionary that carried them. Removed across 23 lang files.

login.setPasswordInstruction is rendered on the new-password screen via the now-canonical login_* namespace; it was missing from en (the fallback), da, nb and sv. Added there using the same translation tone as the existing de/nl entries.

* Login: Honour legacy auth_greeting* overrides with UmbDeprecation warning

Translation packages still shipping 'auth_greeting0..6' overrides keep working on both welcome screens (the standalone login page and the in-backoffice umb-auth-view): when an auth_* greeting is registered the consumer prefers it, otherwise the canonical login_* key is used. Each legacy key triggers a one-time UmbDeprecation warning pointing at the canonical name. Scheduled for removal in v20.

* Fix Prettier formatting and correct issue references in deprecation message

Addresses Copilot review feedback on PR #22743:

- Run Prettier on the 6 backoffice lang files I added keys to (en/da/de/nb/nl/sv); the new entries used double quotes which violated the repo's singleQuote: true config and would have failed the format check.
- Update the UmbDeprecation 'solution' link and the inline source comments from #56402 (an ADO work item id) to #20082 (the actual GitHub issue tracking this work).

* Drop stale login_2fa* and login_mfaSecurityCodeMessage from bs.ts and cy.ts

Surfaced by 'devops/localization/compare-languages.js': bs and cy were the only lang files shipping these keys, and they have no en counterpart. The login_2fa* set is leftover from before the codebase renamed 2fa → mfa in the login flow (the live keys are login_mfa*). login_mfaSecurityCodeMessage is server-side only, like the other email-template keys cleaned up in 53ad52702e0. None of these are referenced anywhere in src/. The user-facing user_2fa* keys (consumed by current-user-mfa modals) are unrelated and untouched.

* Drop dead login_2fa* and login_mfaSecurityCodeMessage from nl, hr, tr

Same pattern as 26bc6211d27 (bs/cy cleanup), surfaced by re-running devops/localization/compare-languages.js after the previous pass:

- nl had both legacy 'login_2fa*' AND the canonical 'login_mfa*' (added in commit 1) sitting side by side after the auth.* → login.* port. Six true duplicates dropped, login_mfa* kept.
- hr and tr shipped legacy 'login_2fa*' that have no en counterpart, no consumer in src/, and no mfa pair locally. Dropped to align with en (the source of truth — every other locale should match it).

- All three files also still carried 'login_mfaSecurityCodeMessage' from the same family of server-side email-template keys cleaned up in 53ad52702e0; removed too.

user_2fa* / member_2fa keys are unrelated and untouched (consumed by current-user-mfa modals).

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-05-11 11:59:58 +01:00
8a73d713cd Login: Consume sibling Umbraco.Web.UI.Client by source for v18 parity (#22591)
* Login: Consume sibling Umbraco.Web.UI.Client by source for v18 parity

The Login project previously depended on the published `@umbraco-cms/backoffice@^17.3.4` npm package for types, while at runtime the importmap served the in-repo v18 backoffice. The version mismatch forced `as any` workarounds and masked real API drift. Since v18 (with UUI 2.0) isn't on npm yet, switch Login to consume the sibling Client via a local `file:` dep so types and runtime align on v18.

Changes:
- Login `package.json`: `@umbraco-cms/backoffice` → `file:../Umbraco.Web.UI.Client`; added `pre{build,dev,watch}` hooks that run a guard script to fail fast when Client's `dist-cms/` is missing.
- Login `scripts/ensure-client-built.mjs`: new guard with a clear "build the Client first" message.
- Login `CLAUDE.md`: documents the contract and build ordering.
- StaticAssets `.csproj`: `BuildLogin` now depends on `BuildBackoffice` so MSBuild (and therefore the Azure pipeline) builds Client before Login automatically.
- Client `src/tsconfig.build.json`: `declaration: true` so `dist-cms/` ships `.d.ts`.
- Client `package.json`: new `build:types` step (`tsc --emitDeclarationOnly --incremental false && tsc-alias`) wired into `build:for:cms` after `build:workspaces`. Vite workspaces wipe their output dirs before rebuilding JS, stripping the tsc-emitted declarations; re-emitting after workspaces restores them. `tsc-alias` rewrites Client-internal path aliases (e.g. `@umbraco-cms/backoffice/external/lit`) to relative paths so sibling consumers can resolve them.
- `copy-to-cms.js`: filter `.d.ts` and `.tsbuildinfo` from the copy to `wwwroot/umbraco/backoffice` — they're only needed by sibling projects consuming `dist-cms` for types, not at runtime.
- `src/external/uui/vite.config.ts`: set `treeshake: false` so per-component `defineElement()` side-effect calls (used by UUI 2.0 for custom-element registration) are preserved in the bundle. Without this, `<uui-button>` etc. never register and the login screen renders empty controls.
- `src/external/uui/index.ts`: bare `import '@umbraco-ui/uui'` to make the side-effect intent explicit.
- Small v18-compat fixes for `Object.groupBy` (TS 8 types): removed stale `@ts-expect-error`, switched to `Object.entries` + `?? []` to satisfy the `Partial<Record>` return type.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address review feedback and fix CI

- Add `ignoreDeprecations: "6.0"` to `tsconfig.json` and the tsconfig generator to silence the TS 6.0 warning about the implicit baseUrl that TypeScript assigns when `paths` is declared. This was the CI `build` failure. The generator is also synced with the user's es2022 → es2024 bump.
- Drop the now-redundant `--declaration` flag from `build:for:npm` (tsconfig.build.json now has `declaration: true`, so the flag was duplicating intent).
- Align Login's `engines` with the Client's (`node >=24.13`, `npm >=11`) so `file:` install doesn't trip EBADENGINE.
- Guard script: hardcode the relative "../Umbraco.Web.UI.Client" path in the error message instead of interpolating the absolute path, which overflowed the ASCII box in CI logs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Login: update CLAUDE.md Node/npm versions to match engines

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* check-path-length: skip .d.ts/.tsbuildinfo and directory paths

The 120-char Windows MAX_PATH guard protects files that actually ship to
CMS installs. `.d.ts` and `.tsbuildinfo` live in `dist-cms/` for sibling
projects to consume as types and are filtered out by `copy-to-cms.js`
before reaching `wwwroot/umbraco/backoffice` — they never land on a
Windows CMS install. Directories on their own also don't trigger
MAX_PATH; only files within them do, and those are still checked.

Unblocks CI after enabling `declaration: true` in the Client build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* check-path-length: extract exceedsPathLimit helper (CodeScene)

Decomposes the complex conditional flagged by CodeScene into a named
predicate with a docstring, clarifying when a path is reported.

* Login: switch to generated tsconfig paths; revert dist-cms type machinery

PR #22591 originally aligned Login's TypeScript types with the in-repo v18
backoffice by emitting `.d.ts` into Client's `dist-cms/` and consuming it
via a `file:` dep. That layered six side-effects across the Client build
(declaration: true, build:types step, tsc-alias in postbuild, copy-to-cms
filter, check:paths skip, MSBuild ordering). Reviewers pushed back.

This rework moves the type contract from "ship .d.ts in dist-cms" to
"point Login's tsconfig paths at Client's TypeScript source" — Login's
runtime behaviour is unchanged (vite still externalises /^@umbraco-cms/,
host importmap still serves the JS), only the type-resolution mechanism
swaps.

What's reverted (back to the pre-PR shape):
- src/Umbraco.Web.UI.Client/src/tsconfig.build.json: declaration: false
- src/Umbraco.Web.UI.Client/package.json: drops `build:types` script,
  reverts `postbuild` to global-types only, drops `--declaration` from
  the tsc CLI in `build:for:cms` and restores it in `build:for:npm`
- src/Umbraco.Web.UI.Client/devops/build/copy-to-cms.js: simple cpSync
- src/Umbraco.Web.UI.Client/devops/build/check-path-length.js: original
- src/Umbraco.Web.UI.Client/tsconfig.json + devops/tsconfig/index.js:
  drops `ignoreDeprecations` (not needed once baseUrl is gone)
- src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj:
  `BuildLogin` no longer depends on `BuildBackoffice`

What's new on the Login side:
- src/Umbraco.Web.UI.Login/devops/tsconfig/index.js: generator that
  reads Client's `package.json` exports and emits a full `tsconfig.json`
  with `paths` mapping every `@umbraco-cms/backoffice/<sub>` to
  `../Umbraco.Web.UI.Client/src/.../index.ts`. Mirrors Client's existing
  generator pattern (DON'T EDIT header, JSON.stringify with tabs).
- src/Umbraco.Web.UI.Login/tsconfig.json: regenerated; standalone `tsc`
  works (no `--project` needed) and 140 path aliases resolve types
  directly from Client's source.
- src/Umbraco.Web.UI.Login/package.json: drops `@umbraco-cms/backoffice`
  npm dep entirely (file: was only nominal — types come via paths,
  runtime via importmap, transitives via Client's own `node_modules`
  which is `npm install`-ed by CI's backoffice-install.yml). Replaces
  the `ensure-client-built` guard with the generator on `pre*` hooks
  and adds `generate:tsconfig` for ad-hoc invocation.
- src/Umbraco.Web.UI.Login/CLAUDE.md: documents the new layered
  contract (paths/externalisation/importmap) and the install-Client-
  before-Login prerequisite.
- src/Umbraco.Web.UI.Login/scripts/ensure-client-built.mjs: deleted.

What stays from the original PR (independent fixes):
- src/Umbraco.Web.UI.Client/src/external/uui/{vite.config.ts,index.ts}:
  `treeshake: false` + bare side-effect import — keeps UUI 2.0
  per-component `defineElement` calls in the bundle so `<uui-button>`
  etc. actually register.
- Object.groupBy cleanups in 6 element files (TS 8 type narrowing).
- Client tsconfig generator: target/lib bumped to ES2024, `baseUrl`
  removed.

Verified locally:
- `cd Client && rm -rf dist-cms && cd ../Login && npx tsc` → clean
  (proves Login compiles without Client's dist-cms)
- `cd Client && npm run build:for:cms` → 0 emitted .d.ts (back to
  pre-PR shape), `check:paths` passes
- Login `npm run build` → 64 KB bundle (unchanged)
- Browser at https://localhost:44339/umbraco: UUI 2.0 components
  render, login with `test@umbraco.com`/`test123456` succeeds and
  redirects to /umbraco/section/content

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Login: address review — idempotent generator + correct MSBuild ordering

- StaticAssets.csproj: BuildLogin now depends on RestoreBackoffice (not
  BuildBackoffice — Login doesn't need dist-cms types). Login's tsc walks
  Client source via tsconfig path aliases and resolves transitive deps
  (lit, rxjs, …) from Client's node_modules. Without this dependency a
  fresh local `dotnet build` could run BuildLogin before Client is
  installed; CI was already safe via backoffice-install.yml's npm ci.

- devops/tsconfig/index.js: skip rewrite when content is unchanged. Pre-
  hooks ran the generator on every npm command and bumped tsconfig.json
  mtime even when nothing changed, which can invalidate caches and rattle
  watchers downstream. Read-then-compare-then-write makes the generator
  truly idempotent.

- devops/tsconfig/index.js: derive the alias prefix from
  `clientPkg.name` instead of hardcoding `@umbraco-cms/backoffice` so a
  package rename can't silently break paths.

azure-pipelines.yml needs no changes — backoffice-install.yml already
runs `npm ci` in Client before dotnet build kicks in MSBuild.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Login: postinstall + dev-mode Vite alias + theme CSS path

Audit cleanup pass on the rework:

- Login package.json: collapse predev/prebuild/prewatch into a single
  postinstall hook. The generator runs whenever npm install/ci runs
  (locally + in CI via RestoreLogin's npm i + the dotnet build chain).
  Removes the per-command "tsconfig.json already up to date" noise.

- Login vite.config.ts: in dev mode (`vite serve`), read `paths` from
  the generated tsconfig.json and apply them as `resolve.alias` so Vite
  can resolve `@umbraco-cms/backoffice/*` to Client source. Vite doesn't
  honor tsconfig `paths` natively — without this `npm run dev` failed
  with "Failed to resolve import @umbraco-cms/backoffice/utils ...".
  Build mode (`vite build`) still externalises the namespace via the
  unchanged rollupOptions.external regex; alias is dev-only.

- Login index.html: UUI 2.0 reorganised CSS — the old
  `@umbraco-ui/uui-css/dist/uui-css.css` path no longer exists. Point
  at `@umbraco-ui/uui/dist/themes/light.css` which is what Client now
  ships. Path is relative through Client's node_modules since Login no
  longer declares a UUI dep itself.

- Client input-entity-user-permission.element.ts: prettier flagged a
  multi-line .map() arrow that should be inline; collapse to one line.

- Login CLAUDE.md: document the postinstall-driven generator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Use Vite 8 native tsconfigPaths; drop helper plugin and trim comments

- Both vite.config.ts files use `resolve.tsconfigPaths: true` instead of the
  `vite-tsconfig-paths` plugin. Plugin and dep removed.
- Trim explanatory comments on csproj target, generator, UUI vite config and
  external/uui/index.ts to conclusions only.

* Login: tsconfig generator fails fast on unsupported exports shapes

Distinguish between the legitimate `.` self-reference (target === null) and
unexpected non-string targets (e.g., conditional exports objects). The latter
now throw with a clear message instead of being silently dropped from `paths`,
which would otherwise produce confusing 'Cannot find module' errors at tsc
time later.

* Login: allow Vite dev server to serve Client's UUI assets

The light.css imported from Client's node_modules pulls Lato fonts via
relative URL, which Vite refuses by default since they sit outside
Login's project root. Extend server.fs.allow to the parent directory
(both sibling projects).

* Client: regenerate tsconfig on postinstall

* Login: keep UUI registrations in dev mode

Vite 8's esbuild dep pre-bundle drops the per-component
`customElements.define()` side-effects in @umbraco-ui/uui (a known UUI
issue with Vite 8). Exclude UUI from optimizeDeps so it's served
unbundled in dev. Re-add the bare side-effect import in external/uui
so the entry module evaluates the chain. Production build is unaffected
(workspace's `treeshake: false` already preserves registrations).

Also document the new MSBuild Login targets in StaticAssets CLAUDE.md.

* Login: clarify why optimizeDeps.exclude is needed for UUI

Tested treeshake.moduleSideEffects: true in optimizeDeps.rollupOptions
on Vite 8 / Rolldown 1.0.0-rc.17 — registrations still get stripped.
Excluding the package from the pre-bundle is the only reliable workaround
until UUI's own Vite 8 upgrade lands. Comment captures the conclusion.

* Roll back Vite 8 → 7 in Client and Login

Vite 8.0.10 ships Rolldown 1.0.0-rc.17 which strips UUI 2.0
`customElements.define()` side-effects during dep pre-bundle, leaving
elements unregistered in dev mode. Rather than ship a v18 release tied
to a non-final Rolldown RC, revert the Vite bump and pick it up again
once Rolldown 1.0 final lands.

Changes:
- Client: vite ^8.0.10 → ^7.3.2; vite-plugin-static-copy ^4.1.0 → ^3.2.0;
  re-add vite-tsconfig-paths plugin; drop native `resolve.tsconfigPaths`.
- Login: vite ^8.0.10 → ^7.3.2; add vite-tsconfig-paths; configure plugin
  with `projects: ['./tsconfig.json', '../Umbraco.Web.UI.Client/tsconfig.json']`
  so it can resolve `@umbraco-cms/backoffice/*` imports inside Client
  source files (which would otherwise lack a discoverable tsconfig in
  Login's project tree). Drop `optimizeDeps.exclude` (no longer needed
  without Rolldown). Keep `server.fs.allow` for the cross-project font.

TypeScript 6 + ES2024 + tsconfig path generator + Login architectural
pivot all stay — those are independent of the Vite version.

Verified:
- Production https://localhost:44339/umbraco — login works
- Login dev http://localhost:5191/ — UUI registers, all custom elements defined
- Client dev http://localhost:5192/ — page loads, navigates to /section/content

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address Copilot review

- vite.config.ts (Login): narrow server.fs.allow from the parent dir to
  Login + Client only, reducing the dev server's read scope.
- external/uui/vite.config.ts (Client): replace blanket `treeshake: false`
  with `moduleSideEffects: (id) => id.includes('@umbraco-ui/uui')` so
  Rollup keeps UUI's per-component registration calls but tree-shakes the
  rest. Bundle stays at 516 KB / 96 registered tags.

* fix merge overwrites

* update package lock

* fix: do not autogenerate tsconfig on postinstall

* removes postinstall script

* chore: generates tsconfig

* chore: update lockfile

* docs: updates claude.md

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-05-11 09:42:28 +00:00
Andreas ZerbstandGitHub f6ac750d09 E2E: QA: Add missing helpers for Content Versioning (#22788)
* Added missing rollback helpers

* Updated helper to match locator
2026-05-11 06:33:44 +02:00
Niels Lyngsø 4b66c114c4 Revert "fix validation filter"
This reverts commit 0bdb1bb1ed.
2026-05-10 20:17:36 +02:00
Niels Lyngsø 0bdb1bb1ed fix validation filter 2026-05-10 20:16:23 +02:00
Niels Lyngsø 3142691e4f Update architecture.md 2026-05-08 15:13:47 +02:00
Niels Lyngsø c813481b4e update UUI for icon manager 2026-05-08 15:11:53 +02:00
Andy Butland 5c1e7e9167 Merge branch 'release/18.0' of https://github.com/umbraco/Umbraco-CMS into release/18.0 2026-05-08 15:06:26 +02:00
2e16b0d38a Tests: Fix PublishedValueFallbackTests after ILocalizationService removal (#22772)
* fix(tests): replace removed ILocalizationService with ILanguageService in PublishedValueFallbackTests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-08 15:05:55 +02:00
Laura NetoandGitHub ab821e0519 Open API: Skip operation ID generation for non-controller endpoints (#22760)
Skip operation ID generation for non-controller endpoints

UmbracoOperationIdTransformer is registered globally for the default
OpenAPI document, so any minimal API endpoint that lands there ran
through it. The transformer threw "This handler operates only on
ControllerActionDescriptor" because its conventions (route prefix
stripping, MapToApiVersion lookup) only make sense for MVC actions.

Return null from the generator and skip the assignment when the action
descriptor isn't a ControllerActionDescriptor. The framework's default
operation ID applies in that case.
2026-05-08 15:05:11 +02:00
11ff2c8039 Tests: Fix PublishedValueFallbackTests after ILocalizationService removal (#22772)
* fix(tests): replace removed ILocalizationService with ILanguageService in PublishedValueFallbackTests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-08 15:02:58 +02:00
Jacob Overgaard 80098706cf chore: ignores default log message for MSW 2026-05-08 13:05:50 +02:00
leekelleher dff3941e1f Merge branch 'v18/dev' 2026-05-08 10:02:00 +01:00
leekelleher 072e362284 Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/variant-state.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/item/document-collection-item-card.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/column-layouts/document-table-column-property-value.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search-result-item.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/url/info-app/document-links-workspace-info-app.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/variant-state.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-split-view-variant-selector.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info.element.ts
2026-05-08 10:01:33 +01:00
b243940ab5 Auth: Un-deprecate getLatestToken and route per-request fetches through it (#22736)
* Auth: un-deprecates getLatestToken and routes per-request fetches through it

getLatestToken is the only public API for "wait for any in-flight refresh,
trigger one if the access token has expired, then return". External and
internal consumers were warned off it without an equivalent replacement:
configureClient only helps @hey-api/openapi-ts clients, and consumers using
axios/ky/native fetch had no other gate.

- Removes the @deprecated JSDoc + UmbDeprecation.warn() call so the public
  surface no longer prints a console warning per call.
- Uses getLatestToken.bind(this) for the auth callback inside configureClient
  and the token callback inside getOpenApiConfiguration so both paths share
  the same #ensureTokenReady gate.
- Replaces the hard-coded `Authorization: Bearer [redacted]` in unlinkLogin
  and #makeLinkTokenRequest with `Bearer ${await getLatestToken()}` so those
  fetches participate in the refresh coordination rather than firing with a
  potentially-revoked cookie.

Also wires the UmbracoExtension template's entrypoint to call
authContext.configureClient(client), matching the v18 template change. The
framework awaits onInit, so this guarantees the API client is fully
configured before any element in the extension can use it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Auth: tightens UmbAuthContext correctness and accepts any hey-api client

Pulls in a batch of non-breaking improvements to UmbAuthContext that came
out of an audit on the back of the un-deprecation work in this PR:

Public surface:
- configureClient(client) now accepts a new structural UmbApiClient type
  (exported from @umbraco-cms/backoffice/http-client). Each @hey-api/openapi-ts
  generation produces a fully-bound Client<…>; the backoffice's umbHttpClient
  and an extension's regenerated client are structurally identical but TS
  treats them as distinct generic instantiations. The widened parameter lets
  extensions wire their own client without `as never` casts at call sites.
  bindDefaultInterceptors keeps its strict typeof umbHttpClient parameter
  (preserving autocomplete inside interceptor callbacks); the cast happens
  once, internally.

Correctness:
- The auth context now holds a single UmbApiInterceptorController, lazy-
  initialised on first configureClient() call. Previously each call
  instantiated a new controller, which re-provided the UmbAuthSignalerContext
  on the host and stacked listeners — visible the moment an extension also
  called configureClient. One controller for the lifetime of the host, all
  configured clients share it.
- completeAuthorizationRequest checks sessionStorage before asking
  window.opener for the PKCE verifier. The previous order hung for the full
  postMessage timeout whenever oauth_complete loaded with a non-OAuth
  window.opener (which is set for ANY window.open target). The opener
  postMessage timeout is also dropped from 5s to 1.5s — a real popup parent
  responds within milliseconds; longer is just wait time for the unrelated-
  opener case.
- The cross-tab 'authorized' BroadcastChannel handler now routes through
  #setSessionLocally so the timestamp math stays in one place. The
  'sessionUpdate' handler still applies pre-computed timestamps directly
  (peer broadcast already did the math) but does so inside the
  #inSessionUpdateCallback guard, so a synchronous session$ observer can no
  longer trigger a spurious /token refresh on top of a peer's update.
- #ensureTokenReady drops its query-then-request pattern. Now always queues
  behind the umb:token-refresh lock with a no-op callback — if the lock is
  free it acquires immediately, if held it waits. Eliminates the race window
  between query() and request().
- destroy() invokes #popupCleanup before tearing down so an in-flight popup
  flow's window-level message listener and closed-poll interval don't leak
  past the context's lifetime. The cleanup helper itself now resolves the
  popup-flow Promise — every termination path (authorized, popup closed,
  superseded by a new flow, context destroyed) is observable to the awaiter
  instead of hanging forever.

Cleanup:
- makeAuthorizationRequest is annotated Promise<void> so the redirect and
  popup branches share an explicit return type.
- unlinkLogin wraps the parsed problem-details payload in a real Error (with
  the original payload exposed on `.cause`) so callers using `instanceof
  Error` or expecting a stack trace get sane behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 10:59:23 +02:00
1c1787c445 Auth: Un-deprecate getLatestToken and route per-request fetches through it (#22736)
* Auth: un-deprecates getLatestToken and routes per-request fetches through it

getLatestToken is the only public API for "wait for any in-flight refresh,
trigger one if the access token has expired, then return". External and
internal consumers were warned off it without an equivalent replacement:
configureClient only helps @hey-api/openapi-ts clients, and consumers using
axios/ky/native fetch had no other gate.

- Removes the @deprecated JSDoc + UmbDeprecation.warn() call so the public
  surface no longer prints a console warning per call.
- Uses getLatestToken.bind(this) for the auth callback inside configureClient
  and the token callback inside getOpenApiConfiguration so both paths share
  the same #ensureTokenReady gate.
- Replaces the hard-coded `Authorization: Bearer [redacted]` in unlinkLogin
  and #makeLinkTokenRequest with `Bearer ${await getLatestToken()}` so those
  fetches participate in the refresh coordination rather than firing with a
  potentially-revoked cookie.

Also wires the UmbracoExtension template's entrypoint to call
authContext.configureClient(client), matching the v18 template change. The
framework awaits onInit, so this guarantees the API client is fully
configured before any element in the extension can use it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Auth: tightens UmbAuthContext correctness and accepts any hey-api client

Pulls in a batch of non-breaking improvements to UmbAuthContext that came
out of an audit on the back of the un-deprecation work in this PR:

Public surface:
- configureClient(client) now accepts a new structural UmbApiClient type
  (exported from @umbraco-cms/backoffice/http-client). Each @hey-api/openapi-ts
  generation produces a fully-bound Client<…>; the backoffice's umbHttpClient
  and an extension's regenerated client are structurally identical but TS
  treats them as distinct generic instantiations. The widened parameter lets
  extensions wire their own client without `as never` casts at call sites.
  bindDefaultInterceptors keeps its strict typeof umbHttpClient parameter
  (preserving autocomplete inside interceptor callbacks); the cast happens
  once, internally.

Correctness:
- The auth context now holds a single UmbApiInterceptorController, lazy-
  initialised on first configureClient() call. Previously each call
  instantiated a new controller, which re-provided the UmbAuthSignalerContext
  on the host and stacked listeners — visible the moment an extension also
  called configureClient. One controller for the lifetime of the host, all
  configured clients share it.
- completeAuthorizationRequest checks sessionStorage before asking
  window.opener for the PKCE verifier. The previous order hung for the full
  postMessage timeout whenever oauth_complete loaded with a non-OAuth
  window.opener (which is set for ANY window.open target). The opener
  postMessage timeout is also dropped from 5s to 1.5s — a real popup parent
  responds within milliseconds; longer is just wait time for the unrelated-
  opener case.
- The cross-tab 'authorized' BroadcastChannel handler now routes through
  #setSessionLocally so the timestamp math stays in one place. The
  'sessionUpdate' handler still applies pre-computed timestamps directly
  (peer broadcast already did the math) but does so inside the
  #inSessionUpdateCallback guard, so a synchronous session$ observer can no
  longer trigger a spurious /token refresh on top of a peer's update.
- #ensureTokenReady drops its query-then-request pattern. Now always queues
  behind the umb:token-refresh lock with a no-op callback — if the lock is
  free it acquires immediately, if held it waits. Eliminates the race window
  between query() and request().
- destroy() invokes #popupCleanup before tearing down so an in-flight popup
  flow's window-level message listener and closed-poll interval don't leak
  past the context's lifetime. The cleanup helper itself now resolves the
  popup-flow Promise — every termination path (authorized, popup closed,
  superseded by a new flow, context destroyed) is observable to the awaiter
  instead of hanging forever.

Cleanup:
- makeAuthorizationRequest is annotated Promise<void> so the redirect and
  popup branches share an explicit return type.
- unlinkLogin wraps the parsed problem-details payload in a real Error (with
  the original payload exposed on `.cause`) so callers using `instanceof
  Error` or expecting a stack trace get sane behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 10:58:19 +02:00
6c5873047b Auth: Un-deprecate getLatestToken and route per-request fetches through it (#22736)
* Auth: un-deprecates getLatestToken and routes per-request fetches through it

getLatestToken is the only public API for "wait for any in-flight refresh,
trigger one if the access token has expired, then return". External and
internal consumers were warned off it without an equivalent replacement:
configureClient only helps @hey-api/openapi-ts clients, and consumers using
axios/ky/native fetch had no other gate.

- Removes the @deprecated JSDoc + UmbDeprecation.warn() call so the public
  surface no longer prints a console warning per call.
- Uses getLatestToken.bind(this) for the auth callback inside configureClient
  and the token callback inside getOpenApiConfiguration so both paths share
  the same #ensureTokenReady gate.
- Replaces the hard-coded `Authorization: Bearer [redacted]` in unlinkLogin
  and #makeLinkTokenRequest with `Bearer ${await getLatestToken()}` so those
  fetches participate in the refresh coordination rather than firing with a
  potentially-revoked cookie.

Also wires the UmbracoExtension template's entrypoint to call
authContext.configureClient(client), matching the v18 template change. The
framework awaits onInit, so this guarantees the API client is fully
configured before any element in the extension can use it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Auth: tightens UmbAuthContext correctness and accepts any hey-api client

Pulls in a batch of non-breaking improvements to UmbAuthContext that came
out of an audit on the back of the un-deprecation work in this PR:

Public surface:
- configureClient(client) now accepts a new structural UmbApiClient type
  (exported from @umbraco-cms/backoffice/http-client). Each @hey-api/openapi-ts
  generation produces a fully-bound Client<…>; the backoffice's umbHttpClient
  and an extension's regenerated client are structurally identical but TS
  treats them as distinct generic instantiations. The widened parameter lets
  extensions wire their own client without `as never` casts at call sites.
  bindDefaultInterceptors keeps its strict typeof umbHttpClient parameter
  (preserving autocomplete inside interceptor callbacks); the cast happens
  once, internally.

Correctness:
- The auth context now holds a single UmbApiInterceptorController, lazy-
  initialised on first configureClient() call. Previously each call
  instantiated a new controller, which re-provided the UmbAuthSignalerContext
  on the host and stacked listeners — visible the moment an extension also
  called configureClient. One controller for the lifetime of the host, all
  configured clients share it.
- completeAuthorizationRequest checks sessionStorage before asking
  window.opener for the PKCE verifier. The previous order hung for the full
  postMessage timeout whenever oauth_complete loaded with a non-OAuth
  window.opener (which is set for ANY window.open target). The opener
  postMessage timeout is also dropped from 5s to 1.5s — a real popup parent
  responds within milliseconds; longer is just wait time for the unrelated-
  opener case.
- The cross-tab 'authorized' BroadcastChannel handler now routes through
  #setSessionLocally so the timestamp math stays in one place. The
  'sessionUpdate' handler still applies pre-computed timestamps directly
  (peer broadcast already did the math) but does so inside the
  #inSessionUpdateCallback guard, so a synchronous session$ observer can no
  longer trigger a spurious /token refresh on top of a peer's update.
- #ensureTokenReady drops its query-then-request pattern. Now always queues
  behind the umb:token-refresh lock with a no-op callback — if the lock is
  free it acquires immediately, if held it waits. Eliminates the race window
  between query() and request().
- destroy() invokes #popupCleanup before tearing down so an in-flight popup
  flow's window-level message listener and closed-poll interval don't leak
  past the context's lifetime. The cleanup helper itself now resolves the
  popup-flow Promise — every termination path (authorized, popup closed,
  superseded by a new flow, context destroyed) is observable to the awaiter
  instead of hanging forever.

Cleanup:
- makeAuthorizationRequest is annotated Promise<void> so the redirect and
  popup branches share an explicit return type.
- unlinkLogin wraps the parsed problem-details payload in a real Error (with
  the original payload exposed on `.cause`) so callers using `instanceof
  Error` or expecting a stack trace get sane behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 10:57:32 +02:00
7248f01292 Auth: Un-deprecate getLatestToken and route per-request fetches through it (#22736)
* Auth: un-deprecates getLatestToken and routes per-request fetches through it

getLatestToken is the only public API for "wait for any in-flight refresh,
trigger one if the access token has expired, then return". External and
internal consumers were warned off it without an equivalent replacement:
configureClient only helps @hey-api/openapi-ts clients, and consumers using
axios/ky/native fetch had no other gate.

- Removes the @deprecated JSDoc + UmbDeprecation.warn() call so the public
  surface no longer prints a console warning per call.
- Uses getLatestToken.bind(this) for the auth callback inside configureClient
  and the token callback inside getOpenApiConfiguration so both paths share
  the same #ensureTokenReady gate.
- Replaces the hard-coded `Authorization: Bearer [redacted]` in unlinkLogin
  and #makeLinkTokenRequest with `Bearer ${await getLatestToken()}` so those
  fetches participate in the refresh coordination rather than firing with a
  potentially-revoked cookie.

Also wires the UmbracoExtension template's entrypoint to call
authContext.configureClient(client), matching the v18 template change. The
framework awaits onInit, so this guarantees the API client is fully
configured before any element in the extension can use it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Auth: tightens UmbAuthContext correctness and accepts any hey-api client

Pulls in a batch of non-breaking improvements to UmbAuthContext that came
out of an audit on the back of the un-deprecation work in this PR:

Public surface:
- configureClient(client) now accepts a new structural UmbApiClient type
  (exported from @umbraco-cms/backoffice/http-client). Each @hey-api/openapi-ts
  generation produces a fully-bound Client<…>; the backoffice's umbHttpClient
  and an extension's regenerated client are structurally identical but TS
  treats them as distinct generic instantiations. The widened parameter lets
  extensions wire their own client without `as never` casts at call sites.
  bindDefaultInterceptors keeps its strict typeof umbHttpClient parameter
  (preserving autocomplete inside interceptor callbacks); the cast happens
  once, internally.

Correctness:
- The auth context now holds a single UmbApiInterceptorController, lazy-
  initialised on first configureClient() call. Previously each call
  instantiated a new controller, which re-provided the UmbAuthSignalerContext
  on the host and stacked listeners — visible the moment an extension also
  called configureClient. One controller for the lifetime of the host, all
  configured clients share it.
- completeAuthorizationRequest checks sessionStorage before asking
  window.opener for the PKCE verifier. The previous order hung for the full
  postMessage timeout whenever oauth_complete loaded with a non-OAuth
  window.opener (which is set for ANY window.open target). The opener
  postMessage timeout is also dropped from 5s to 1.5s — a real popup parent
  responds within milliseconds; longer is just wait time for the unrelated-
  opener case.
- The cross-tab 'authorized' BroadcastChannel handler now routes through
  #setSessionLocally so the timestamp math stays in one place. The
  'sessionUpdate' handler still applies pre-computed timestamps directly
  (peer broadcast already did the math) but does so inside the
  #inSessionUpdateCallback guard, so a synchronous session$ observer can no
  longer trigger a spurious /token refresh on top of a peer's update.
- #ensureTokenReady drops its query-then-request pattern. Now always queues
  behind the umb:token-refresh lock with a no-op callback — if the lock is
  free it acquires immediately, if held it waits. Eliminates the race window
  between query() and request().
- destroy() invokes #popupCleanup before tearing down so an in-flight popup
  flow's window-level message listener and closed-poll interval don't leak
  past the context's lifetime. The cleanup helper itself now resolves the
  popup-flow Promise — every termination path (authorized, popup closed,
  superseded by a new flow, context destroyed) is observable to the awaiter
  instead of hanging forever.

Cleanup:
- makeAuthorizationRequest is annotated Promise<void> so the redirect and
  popup branches share an explicit return type.
- unlinkLogin wraps the parsed problem-details payload in a real Error (with
  the original payload exposed on `.cause`) so callers using `instanceof
  Error` or expecting a stack trace get sane behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:54:04 +01:00
Laura NetoandGitHub 317e9b4e69 Elements: Disable inaccessible parent folders in element tree (#22749)
Disable inaccessible parent folders in element tree

When an element start node is configured to a child folder, the backend
returns ancestor folders flagged with NoAccess so they show as breadcrumbs.
The element folder tree item used the default tree item element, which
does not observe noAccess, so parent folders rendered as enabled and
clickable in the Library section tree. Added a custom
element-folder-tree-item element that observes the context's noAccess and
forwards it to the base, which already handles disabling the menu item.
2026-05-08 09:51:24 +01:00
leekelleher 4fab629ee3 Documents: Alias DocumentVariantStateModel API model for backoffice client (#22716)
* Client: Aliased `DocumentVariantStateModel` for documents and document-blueprints packages

Hoist `UmbDocumentVariantState` and `UmbDocumentBlueprintVariantState` aliases (re-exporting `DocumentVariantStateModel`) into dedicated `variant-state.ts` leaf files. Internal package modules, mocks and the core split-view selector now consume the alias instead of referencing `DocumentVariantStateModel` directly, mirroring the structure on `v18/dev` to reduce upstream-merge conflicts.

* Revert mock data changes

to prevent importing the whole "document" module.

* Tweaked the `DocumentVariantStateModel` import for mock data

Otherwise this is problematic for cherry-picked commits for v18.0.

* Missed one!
# Conflicts:
#	src/Umbraco.Web.UI.Client/mocks/data/sets/default/document-blueprint.data.ts
#	src/Umbraco.Web.UI.Client/mocks/data/sets/default/document.data.ts
#	src/Umbraco.Web.UI.Client/mocks/data/sets/kitchen-sink/document.data.ts
#	src/Umbraco.Web.UI.Client/mocks/data/sets/user-permissions/document.data.ts
#	src/Umbraco.Web.UI.Client/mocks/db/document-blueprint.db.ts
#	src/Umbraco.Web.UI.Client/mocks/db/document-publishing.manager.ts
#	src/Umbraco.Web.UI.Client/mocks/db/document.db.ts
#	src/Umbraco.Web.UI.Client/mocks/tools/sqlite-to-mock/transform-documents.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/repository/item/types.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/types.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/item/document-collection-item-card.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/column-layouts/document-table-column-property-value.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search-result-item.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/url/info-app/document-links-workspace-info-app.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/variant-state.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-split-view-variant-selector.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info.element.ts
2026-05-08 09:49:55 +01:00
Andy Butland 221531b614 Published Content: Fix Fallback.ToAncestors with no match throwing exception at property level (closes #22759) (#22763)
* Fix Fallback.ToAncestors regression at property level.

* Further unit tests.
2026-05-08 10:32:18 +02:00
leekelleher 8495405927 Documents: Alias DocumentVariantStateModel API model for backoffice client (#22716)
* Client: Aliased `DocumentVariantStateModel` for documents and document-blueprints packages

Hoist `UmbDocumentVariantState` and `UmbDocumentBlueprintVariantState` aliases (re-exporting `DocumentVariantStateModel`) into dedicated `variant-state.ts` leaf files. Internal package modules, mocks and the core split-view selector now consume the alias instead of referencing `DocumentVariantStateModel` directly, mirroring the structure on `v18/dev` to reduce upstream-merge conflicts.

* Revert mock data changes

to prevent importing the whole "document" module.

* Tweaked the `DocumentVariantStateModel` import for mock data

Otherwise this is problematic for cherry-picked commits for v18.0.

* Missed one!
# Conflicts:
#	src/Umbraco.Web.UI.Client/mocks/data/sets/default/document-blueprint.data.ts
#	src/Umbraco.Web.UI.Client/mocks/data/sets/default/document.data.ts
#	src/Umbraco.Web.UI.Client/mocks/data/sets/kitchen-sink/document.data.ts
#	src/Umbraco.Web.UI.Client/mocks/data/sets/user-permissions/document.data.ts
#	src/Umbraco.Web.UI.Client/mocks/db/document-blueprint.db.ts
#	src/Umbraco.Web.UI.Client/mocks/db/document-publishing.manager.ts
#	src/Umbraco.Web.UI.Client/mocks/db/document.db.ts
#	src/Umbraco.Web.UI.Client/mocks/tools/sqlite-to-mock/transform-documents.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/repository/item/types.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/types.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/item/document-collection-item-card.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/column-layouts/document-table-column-property-value.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search-result-item.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/url/info-app/document-links-workspace-info-app.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/variant-state.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-split-view-variant-selector.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info.element.ts
2026-05-08 09:23:36 +01:00
Andy Butland a434ad7b33 Published Content: Fix Fallback.ToAncestors with no match throwing exception at property level (closes #22759) (#22763)
* Fix Fallback.ToAncestors regression at property level.

* Further unit tests.
2026-05-08 10:19:00 +02:00
Andy Butland 3714ebbb29 Published Content: Fix Fallback.ToAncestors with no match throwing exception at property level (closes #22759) (#22763)
* Fix Fallback.ToAncestors regression at property level.

* Further unit tests.
2026-05-08 10:18:09 +02:00
Andy Butland 58b047bf7e Published Content: Fix Fallback.ToAncestors with no match throwing exception at property level (closes #22759) (#22763)
* Fix Fallback.ToAncestors regression at property level.

* Further unit tests.
2026-05-08 10:17:20 +02:00
Andy ButlandandGitHub 1a74aa53c9 Published Content: Fix Fallback.ToAncestors with no match throwing exception at property level (closes #22759) (#22763)
* Fix Fallback.ToAncestors regression at property level.

* Further unit tests.
2026-05-08 10:15:28 +02:00
Andy Butland 1214771847 Bump version to 17.6.0-rc. 2026-05-08 10:07:34 +02:00
Lee KelleherandGitHub 396497a921 Documents: Alias DocumentVariantStateModel API model for backoffice client (#22716)
* Client: Aliased `DocumentVariantStateModel` for documents and document-blueprints packages

Hoist `UmbDocumentVariantState` and `UmbDocumentBlueprintVariantState` aliases (re-exporting `DocumentVariantStateModel`) into dedicated `variant-state.ts` leaf files. Internal package modules, mocks and the core split-view selector now consume the alias instead of referencing `DocumentVariantStateModel` directly, mirroring the structure on `v18/dev` to reduce upstream-merge conflicts.

* Revert mock data changes

to prevent importing the whole "document" module.

* Tweaked the `DocumentVariantStateModel` import for mock data

Otherwise this is problematic for cherry-picked commits for v18.0.

* Missed one!
2026-05-08 08:04:07 +00:00
Jacob OvergaardandClaude Sonnet 4.6 80cc752b3d Backoffice Mocks: Add missing element start node fields to documents mock set
`elementStartNodeIds` and `hasElementRootAccess` were added to
`UmbCurrentUserModel` by the Global Elements PR but the documents mock
data set was created without them, causing `undefined.map()` errors in
the document workspace CRUD tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 09:08:40 +02:00
Jacob Overgaard 39125da978 Merge remote-tracking branch 'origin/main' into v18/dev 2026-05-08 09:03:36 +02:00
Niels Lyngsø bf32f9e5a6 update package-lock 2026-05-08 09:01:20 +02:00
Niels Lyngsø 3220739faa upgrade to UI LIbrary 1.17.3 2026-05-08 08:59:49 +02:00
Niels Lyngsø ff565b95e0 update package-lock 2026-05-08 08:54:28 +02:00
Niels Lyngsø 93a1f82b05 Merge branch 'release/17.4.0'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
#	version.json
2026-05-08 08:53:57 +02:00
Jacob OvergaardandGitHub ae4ac2a4b9 build(deps): bumps @umbraco-ui/uui to 1.17.3 (#22753) 2026-05-08 08:52:11 +02:00
Andreas ZerbstandGitHub 54ded689e8 E2E: QA: Add .prettierrc.json to acceptance tests for formatting consistency (#22751)
Add .prettierrc.json to acceptance tests for formatting consistency
2026-05-08 09:19:26 +07:00
Jacob Overgaard 1c32829883 chore: fixes to use correct import of api types in mock data 2026-05-07 21:26:53 +02:00
Andy ButlandandJacob Overgaard dc446c0e4a Color Picker: Refresh stored label when data type label changes (closes #22741) (#22761)
* Update stored color label if changed on save of document with color picker.

* Clarify intent of change event dispatch in label sync

* Make comparison case insensitive.

* Added unit tests for new behaviour.
2026-05-07 21:17:00 +02:00
Jacob Overgaard 1e59af34ff Merge remote-tracking branch 'origin/main' into v18/dev 2026-05-07 21:16:24 +02:00
Andy ButlandandJacob Overgaard 17e73eee28 Color Picker: Refresh stored label when data type label changes (closes #22741) (#22761)
* Update stored color label if changed on save of document with color picker.

* Clarify intent of change event dispatch in label sync

* Make comparison case insensitive.

* Added unit tests for new behaviour.
2026-05-07 21:14:52 +02:00
Andy ButlandandGitHub 2292b7479d Color Picker: Refresh stored label when data type label changes (closes #22741) (#22761)
* Update stored color label if changed on save of document with color picker.

* Clarify intent of change event dispatch in label sync

* Make comparison case insensitive.

* Added unit tests for new behaviour.
2026-05-07 21:13:05 +02:00
Andy Butland ab1be601f5 Dictionary: Order SQL before FetchOneToMany to prevent duplicate items in collection view (closes #22640) (#22750)
* Order SQL before FetchOneToMany in dictionary entry retrieval to prevent duplicate items in collection view.

* Used PrimaryKey instead of UniqueId to take advantage of the clustered index.
2026-05-07 18:45:25 +02:00
Andy Butland 1baf4e5a5c Merge branch 'main' into v18/dev 2026-05-07 18:43:56 +02:00
Andy ButlandandGitHub 9b1fc50de3 Dictionary: Order SQL before FetchOneToMany to prevent duplicate items in collection view (closes #22640) (#22750)
* Order SQL before FetchOneToMany in dictionary entry retrieval to prevent duplicate items in collection view.

* Used PrimaryKey instead of UniqueId to take advantage of the clustered index.
2026-05-07 14:29:43 +00:00
Jacob Overgaard bcf9bf3f3a Merge branch 'release/18.0' into v18/dev 2026-05-07 16:23:19 +02:00
Niels Lyngsø e4dce93b79 Merge branch 'main' into v18/dev
# Conflicts:
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/ContentUiHelper.ts
2026-05-07 14:06:36 +02:00
Niels Lyngsø b07e908ce3 Document Workspace: Add CRUD and property value tests for document workspace context (#22621)
* temp mock set

* test getPropertyValue

* Extend document workspace context tests to cover read/write property values

* move context files into context folder

* Add document CRUD tests, mock handler & interceptor

* temp mock error interceptor

* Return 404 when document not found

* Use undefined for entity unique state until initialized

* Fix import paths for document workspace editor

* Add test utils and extend document workspace tests

* Update document-workspace-context.test-utils.ts

* Match invariant variant when variantId missing

* Ensure finishPropertyValueChange runs on exit

Wrap setPropertyValue implementation in a try/finally and move finishPropertyValueChange into the finally block so cleanup always runs even if an error is thrown. No other functional changes — code was re-indented and organized but behavior remains the same except for guaranteed cleanup on error.

* Require variantId for culture/segment-variant props

* fix types

* fix mock modal typescript error

* Distinguish unloaded vs root entity unique

* use the real current user context

* hide mock set in UI

* rename mock set

* Move initiatePropertyValueChange into try

* Use 'satisfies' for UmbMockDataSet assertions

* Preserve requested unique on failed load

* Treat missing variantId as invariant

* Reset update lock on destroy

* remove unused group + user

* Guard _current.unmute and remove destroy override

* Add tests for element data manager

* Guard subject access and add destroy test

* Throw when calling methods after destroy
2026-05-07 14:00:34 +02:00
3052b57203 E2E: QA: add acceptance tests for content versioning (#22702)
* Added tests

* Updated

* Cleaned up

* Fixes based on comments

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Added helpers for verifying document

* Removed redundant method

* Cleaned up

* Reverted deletion of constants

* Undo revert

* Fixes based on comments

* updated command

* Added removed method

* Update smokeTest command in package.json

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-07 10:13:29 +00:00
aba8e3eb7a Icons: developer icon manager (#22437)
* extend icons with information from theseaurus

* implement new icon search logic

* clean-up data

* icon manager

* sorting with a backup of the name

* refactor into a controller

* improve multi word group search

* embed lucide data

* rename tech into technology

* remove paper from dollar

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* improve search

* related should not show up in search

* update threshold

* separate name words

* also consider full icon name match

* better comment

* other approach for full name matches

* full icon name search if query contains a -

* fix test

* remove related code

* updates to related

* make its own package

* revert changes

* update tsconfig

* package-lock

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-07 10:11:05 +00:00
Lee KelleherandGitHub 41a9133c58 V18: Reverts removal of property-value-change event listeners (#22734)
* Reverts removal of `property-value-change` event listeners

* Adds `UmbDeprecation` warning

for `property-value-change` events.
2026-05-07 09:27:05 +00:00
4953855dda Build: Upgrade @hey-api/openapi-ts to 0.97 (#22735)
* build(deps): updates @hey-api/openapi-ts to latest and regenerates APi types

* build(deps): updates @hey-api/openapi-ts to latest and regenerates APi types (login)

* fix(backoffice): avoid invalid status 0 when synthesizing responses

Default to a 500 fallback status when no upstream Response is provided
to #createResponse, preventing a RangeError from the Response constructor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* build(deps): updates UmbracoExtension template to @hey-api/openapi-ts 0.97

- Bumps @hey-api/openapi-ts to ^0.97.0 in the extension template.
- Simplifies the generate-openapi.js plugin config: spread @hey-api defaults
  and only override @hey-api/sdk with responseStyle: 'fields' so call sites
  keep the { data, error } destructuring shape. Removes the redundant
  @hey-api/client-fetch redeclaration that triggered duplicate-plugin warnings.
- Drops the hey-api.ts runtime config file in favour of wiring the generated
  client through UMB_AUTH_CONTEXT.configureClient() from the entrypoint, so
  extensions inherit the same auth callback and default response interceptors
  (401 retry, error notifications) as the core backoffice.
- Regenerates the pre-bundled SDK against the template's canonical
  Umbraco.Extension scaffold so it matches what `npm run generate-client`
  produces on first run; default hey-api output is flat function exports.
- Updates dashboard.element.ts call sites to match the new SDK shape and
  renames the user model usage to Iuser to follow the new schema.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(git): marks UmbracoExtension template generated SDK as linguist-generated

So GitHub diffs collapse the regenerated *.gen.ts files in PRs, matching what
we already do for the backoffice client and Login app SDKs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(template): addresses review feedback on PR #22735

- Restores the regenerated SDK's hard-coded baseUrl to https://localhost:44339/
  so the SiteDomain template token in the .template.config still substitutes
  it at scaffold time. The 5443 port leaked in from the local host I used to
  regenerate; that domain is replaced by the user's chosen SiteDomain on
  scaffold.
- Stops marking onInit as `async`. The UmbEntryPointOnInit signature returns
  void; making the hook async is harmless under TS's bivariant void-return
  assignability but is misleading. Kicks the context resolution + client
  configuration off via .then() and logs a warning when UMB_AUTH_CONTEXT is
  not present (instead of silently optional-chaining).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(template): keeps onInit async — the framework awaits it

The previous tweak was based on Copilot's claim that UmbEntryPointOnInit
returns void. The signature does declare void, but the entry-point
initializer in app-entry-point-extension-initializer.ts and
backoffice-entry-point-extension-initializer.ts both `await
moduleInstance.onInit(...)`, so an async onInit is awaited end-to-end.
Reverting to async ensures configureClient runs to completion before any
element in the extension can hit the API client.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 09:11:59 +00:00
Mads RasmussenandGitHub 040a0d5e49 Document Workspace: Add CRUD and property value tests for document workspace context (#22621)
* temp mock set

* test getPropertyValue

* Extend document workspace context tests to cover read/write property values

* move context files into context folder

* Add document CRUD tests, mock handler & interceptor

* temp mock error interceptor

* Return 404 when document not found

* Use undefined for entity unique state until initialized

* Fix import paths for document workspace editor

* Add test utils and extend document workspace tests

* Update document-workspace-context.test-utils.ts

* Match invariant variant when variantId missing

* Ensure finishPropertyValueChange runs on exit

Wrap setPropertyValue implementation in a try/finally and move finishPropertyValueChange into the finally block so cleanup always runs even if an error is thrown. No other functional changes — code was re-indented and organized but behavior remains the same except for guaranteed cleanup on error.

* Require variantId for culture/segment-variant props

* fix types

* fix mock modal typescript error

* Distinguish unloaded vs root entity unique

* use the real current user context

* hide mock set in UI

* rename mock set

* Move initiatePropertyValueChange into try

* Use 'satisfies' for UmbMockDataSet assertions

* Preserve requested unique on failed load

* Treat missing variantId as invariant

* Reset update lock on destroy

* remove unused group + user

* Guard _current.unmute and remove destroy override

* Add tests for element data manager

* Guard subject access and add destroy test

* Throw when calling methods after destroy
2026-05-07 09:36:05 +02:00
Laura Neto 6201c3dc40 Bump version to 18.1.0-rc 2026-05-06 19:15:46 +02:00
Laura Neto 0c08d522a2 Adjust Umbraco.Tests.AcceptanceTest version to 18.0.0-beta1 2026-05-06 19:05:48 +02:00
Laura Neto 10a656c067 Merge branch 'main' into v18/dev 2026-05-06 18:55:54 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Jacob Overgaard
ef01edb46a Bump lodash from 4.17.21 to 4.18.1 in /src/Umbraco.Web.UI.Client (#22723)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-05-06 16:47:05 +00:00
Laura NetoandGitHub 6067d428d0 Delivery API: Fix broken discriminator mapping refs for polymorphic schemas (#22733)
* Delivery API: Fix broken discriminator mapping refs for polymorphic schemas

Microsoft.AspNetCore.OpenApi's MapPolymorphismOptionsToDiscriminator builds each ref as callback(base) + callback(derived), but our typed-schema flow registers the derived schemas without the base prefix. The auto-built mapping refs end up pointing at non-existent schemas, which crashes strict client generators like orval.

Strip the base schema id from the front of each broken ref to recover the registration key the derived schema actually uses.

* Delivery API: Add integration test coverage for the polymorphic discriminator mapping fix

Adds a test-only property editor whose Delivery API value type is a polymorphic interface declared with [JsonDerivedType], wired into the existing typed-schema integration test fixture. The OpenApiContract_HasExpectedSchemas test verifies that the auto-built discriminator mapping refs resolve to the registered derived schema names, providing end-to-end regression coverage for the fix.

Also extends AssertSchemaIsPolymorphicUnion to accept either oneOf (used by our typed schema unions) or anyOf (used by framework-built unions for [JsonDerivedType] interfaces).

* Use a captured schemas local in FixAutoBuiltDiscriminatorMapping

Move the null check for document.Components.Schemas into the top-of-method guard and use the captured non-null local in the loop body. Avoids both the null-conditional ?. operators and the null-forgiving ! operator at the use sites.
2026-05-06 17:09:44 +02:00
Andy Butland bf5f82607e Merge branch 'main' into v18/dev 2026-05-06 16:25:30 +02:00
8ab68b574f Backoffice: Add localize.htmlString() helper to prevent XSS in HTML-rendered translations (#22731)
* docs(claude): document how unsafeHTML should be used together with escapeHTML()

* fix: adds escapeHTML where appropriate in order not to render html directly

* chore: removes small nitpick fallback

* docs(claude): fixes incorrect using of unsafeHTML

* feat(localization): add localize.htmlString() and convert call sites

Adds a new `htmlString()` method on UmbLocalizationController that escapes
interpolated args via escapeHTML and returns a Lit unsafeHTML directive.
This is the safe replacement for the manual `unsafeHTML(this.localize.string(...))`
pattern, which leaves user-controlled args un-escaped (XSS hazard).

Converts all direct `unsafeHTML(localize.string|term(...))` call sites
across modals, rollback views, packager, property editors, and entity
actions. Also fixes the latent XSS in `trash.action.ts` (sibling of the
previously-fixed `delete.action.ts`).

Updates docs/security.md with guidance on `string()` vs `htmlString()`
and the modal-content wrapping pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(eslint): add no-unsafe-localize rule to flag unsafeHTML(localize.string|term(...))

Catches the XSS pattern this PR's helper replaces, so future regressions
are caught at lint time instead of in review (or in a security advisory).
Suggests `localize.htmlString(...)` as the safe replacement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(localization): stringify htmlString args before escaping

Addresses review feedback on PR #22731. escapeHTML() short-circuits on
non-strings (returns the value unchanged), so an arg like
{ toString: () => '<script>...</script>' } would bypass the escape and
render unescaped via unsafeHTML.

Stringifies args before escaping while preserving `undefined` so
string()'s placeholder semantics are unchanged. Adds a regression test
covering the toString() bypass.

Also adds the missing html/unsafeHTML imports to the security.md
example so the snippet is self-contained.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(installer-consent-element): sanitise content before rendering it

* fix(dashboard-telem-element): sanitise html before rendering

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: LLaverty <liamlaverty@gmail.com>
2026-05-06 16:11:47 +02:00
7c6b755ca5 Backoffice: Add localize.htmlString() helper to prevent XSS in HTML-rendered translations (#22731)
* docs(claude): document how unsafeHTML should be used together with escapeHTML()

* fix: adds escapeHTML where appropriate in order not to render html directly

* chore: removes small nitpick fallback

* docs(claude): fixes incorrect using of unsafeHTML

* feat(localization): add localize.htmlString() and convert call sites

Adds a new `htmlString()` method on UmbLocalizationController that escapes
interpolated args via escapeHTML and returns a Lit unsafeHTML directive.
This is the safe replacement for the manual `unsafeHTML(this.localize.string(...))`
pattern, which leaves user-controlled args un-escaped (XSS hazard).

Converts all direct `unsafeHTML(localize.string|term(...))` call sites
across modals, rollback views, packager, property editors, and entity
actions. Also fixes the latent XSS in `trash.action.ts` (sibling of the
previously-fixed `delete.action.ts`).

Updates docs/security.md with guidance on `string()` vs `htmlString()`
and the modal-content wrapping pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(eslint): add no-unsafe-localize rule to flag unsafeHTML(localize.string|term(...))

Catches the XSS pattern this PR's helper replaces, so future regressions
are caught at lint time instead of in review (or in a security advisory).
Suggests `localize.htmlString(...)` as the safe replacement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(localization): stringify htmlString args before escaping

Addresses review feedback on PR #22731. escapeHTML() short-circuits on
non-strings (returns the value unchanged), so an arg like
{ toString: () => '<script>...</script>' } would bypass the escape and
render unescaped via unsafeHTML.

Stringifies args before escaping while preserving `undefined` so
string()'s placeholder semantics are unchanged. Adds a regression test
covering the toString() bypass.

Also adds the missing html/unsafeHTML imports to the security.md
example so the snippet is self-contained.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(installer-consent-element): sanitise content before rendering it

* fix(dashboard-telem-element): sanitise html before rendering

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: LLaverty <liamlaverty@gmail.com>
2026-05-06 16:11:14 +02:00
Sven GeusensandGitHub b2ba4abd7e Code Tidy: Remove obsolete MoveEventInfo.NewParent (#22728)
* Removed obsoleted property

Updated methods that were still using it
Obsoleted constructors that were still setting the value.

* Updated code that were using the now obsoleted constructors

* More obsoleted constructor fixes

* Update unittests

Removed obsolete (parentId) cases and updated constructors

* DRY up constructor
2026-05-06 13:21:22 +00:00
2ac2b3e4fa Fix main branch after merge issue (#22729)
* Revert "MD files for Design knowledge (#22725)"

This reverts commit 212f3183c1.

* Revert "Backoffice Mocks: Derive user language access from user groups (#22721)"

This reverts commit 9671fec9ad.

* Revert "File-system Services: Complete child scopes on read-miss and validation-failure paths (#22717)"

This reverts commit 489d9ebc2e.

* Revert "manual revert of merge gone wrong"

This reverts commit a443f8ba08.

* Revert "fix(installer-user): added min length message for installer user elem… (#21829)"

This reverts commit 6789d7e757.

* Reapply "Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS into claude/keen-nightingale-5ef5bd"

This reverts commit daecbd02b8.

* fix(installer-user): added min length message for installer user elem… (#21829)

* fix(installer-user): added min length message for installer user element.

* Update src/Umbraco.Web.UI.Client/src/apps/installer/user/installer-user.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix password minlength message binding syntax

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Emma L Garland <1649855+emmagarland@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>

* File-system Services: Complete child scopes on read-miss and validation-failure paths (#22717)

* Ensure scopes in FolderServiceOperationBase are completed.

* Added integration tests to verify the fixes.

* Backoffice Mocks: Derive user language access from user groups (#22721)

fix(mocks): derive user language access from user groups

Previously hasAccessToAllLanguages was hardcoded to true and languages to
an empty array. Now both are derived from the user's user group memberships.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* MD files for Design knowledge (#22725)

* Fix issues following merge.

* Fixed linting errors.

* Fix linter errors (2).

* Restore current-user.context.ts

* Restore block-list-entry.element.ts.

* Removed failing webhook repository test files.

---------

Co-authored-by: Yari Mariën <75362020+Yinzy00@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Emma L Garland <1649855+emmagarland@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 15:01:05 +02:00
fec0cac557 Delivery API: Generate typed OpenAPI schemas per content type (#22666)
* Delivery API: Generate typed OpenAPI schemas per content type

* Honour Delivery API allow/deny list in typed OpenAPI schemas

ContentTypeSchemaTransformer now filters DocumentTypes through
DeliveryApiSettings.IsAllowedContentType so document types blocked
by AllowedContentTypeAliases / DisallowedContentTypeAliases no longer
leak into the polymorphic union or discriminator mapping.

* Stop registering media derived types in the JSON resolver

ContentJsonTypeResolverBase.GetDerivedTypes goes back to returning
empty. Previously it registered ApiMediaWithCrops and
ApiMediaWithCropsResponse as derived types of their interfaces, which
made every consumer of the resolver (the Delivery API and webhooks)
emit a $type discriminator on media payloads, even when the typed
schema feature was disabled.

The Delivery API still needs a base schema for the typed media
schemas to extend via allOf. Since the concrete media classes are
internal to Umbraco.Infrastructure and cannot be referenced from
[JsonDerivedType] in Core, ContentTypeSchemaTransformer now builds
that base from the interface's own properties when the interface has
no [JsonDerivedType] entries. Content/element interfaces are
unaffected and keep using their declared concrete derived types.

Snapshots regenerated.

* Drop default JsonDerivedType registrations from Delivery API interfaces

Removes the [JsonDerivedType] attributes from IApiContent,
IApiContentResponse, and IApiElement. Without them System.Text.Json
configures no polymorphism by default, so wire payloads stop carrying
$type fields and the OpenAPI spec stops emitting a discriminator on
the generic schemas - matching v17 Delivery API behaviour. Consumers
that need polymorphic serialization can still register derived types
via ContentJsonTypeResolverBase.

Snapshots regenerated.

* Allows nulls at property reference sites without mutating any shared component schema.
Avoid unnecessary re-get of the JsonTypeInfo for the default case.

* Updated expected contracts following code adjustments

* Drop additionalProperties: false from typed schemas

JSON Schema 2020-12 (mandated by OpenAPI 3.1) does not let additionalProperties look through allOf, so a strict validator rejects every inherited field on the composed *ResponseModel/*Model/*PropertiesModel schemas. Most code generators silently ignore it, but the document is technically invalid and the constraint would be a lie anyway since Umbraco can grow new properties in non-major releases.

Removed from all four schema construction sites (response, content type, properties, and the interface-based fallback) and regenerated the affected snapshots.

* Preserve casing of content type aliases in OpenAPI schema IDs

Replaces the legacy ModelsBuilder-style ToCleanString tokenizer with
ToFirstUpperInvariant. The tokenizer split aliases on case boundaries
and mangled capital-letter runs (e.g. "xMLSitemap" -> "XMlsitemap"),
making the typed schema names harder to read for OpenAPI consumers.
Since content type aliases are already valid identifiers, only the
first character needs uppercasing.

Also adds an "xMLSitemap" sample type to the integration tests to
cover the casing-preservation behavior.

* Qualify properties model schema IDs by item type

Document, element, and media types share the same alias namespace
across content/media (a doc-type and a media-type can use the same
alias), so a "{Schema}PropertiesModel" naming scheme could collide.

Properties model schemas now follow the same Content/Element/Media
suffix as their parent *Model schema:

- Document type: ArticlePageContentPropertiesModel
- Element type:  TestElementElementPropertiesModel
- Media type:    VideoMediaPropertiesModel

Composition references look up each composition's own IsElement so
that a doc-type composing an element-type (allowed in the UI) still
references the correct ElementPropertiesModel schema.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-06 12:37:15 +00:00
1bda1c0ef6 Global Elements: User permissions for Element Folders (#22274)
* feat(elements): add granular user permissions for element folders

Add element-folder entity type to applicable entityUserPermission
manifests (Create, Read, Update, Delete, Move) and register a
separate userGranularPermission with a folder-only picker component.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(elements): separate element folder permissions into own directory

Move element-folder entityUserPermission and userGranularPermission
manifests into folder/user-permissions/ with dedicated component.
Revert element manifests to element-only forEntityTypes. Also adds
permission condition to folder update entity action and filters
permission names by entity type.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Corrects the type-safety of the "selected" event

* Commented out `userGranularPermission` manifest for Element Folders

* Added specific permission verbs for Element Folders

* Added Element Folder User Permission condition

* Updated entity-action manifest conditions

for Element Folder permissions

* Updated permission prefixes

from `Umb.ElementFolder.` to match the server `Umb.ElementContainer.`

* Add explicit element folder permission handling

* The ElementPermissionService should not authorize against element containers anymore

* More granular read permission handling for trees

* Rename ElementFolder to ElementContainer

* Export element folder user permission constants from @umbraco-cms/backoffice/element

The 6 new element folder permission constants were not re-exported
through the element package barrel, causing the export-consts test
to fail.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Updated manifest conditions for Element Folder delete permission

* Enforce update permission on element folder name field

Added nameWriteGuard rule to the element folder workspace context
that blocks renaming when the user lacks the
Umb.ElementContainer.Update permission.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix casing

* Fix incorrect condition aliases on element folder actions

- Remove trashed condition from folderCreateOption (create options modal
  already handles this via the parent create action's conditions)
- Use folder-specific permission condition alias on recycle-bin folder
  trash action instead of the generic element permission condition

* Renamed to `ElementContainerPermissionPresentationModel`

to match the server's future naming of this model.

* refactor(elements): apply review feedback for folder permissions

- Switch nameWriteGuard to fallbackToNotPermitted policy, so the rename
  guard expresses intent as "default deny, allow when permitted" rather
  than relying on a permitted:false rule cleared by the condition.
- Rename #enforceUpdatePermission to #setupNameWritePermissions for
  clarity (the method now manages a positive-grant rule).
- Make condition's #elementFolderPermissions and #fallbackPermissions
  optional so "not loaded" is distinguishable from "loaded empty";
  bail out early in #checkPermissions until both have populated, to
  avoid evaluating permissions against incomplete data.
- Drop constructor consumption of UMB_MODAL_MANAGER_CONTEXT in the
  granular permission input element; resolve the modal manager via
  getContext at call time inside the two action methods that need it.

* Add missing using to fix the failing build

* updates server api types

* Fix build error after clean-ups

* Fixes FE build error

Temporarily defines the `IPermissionPresentationModelElementContainerPermissionPresentationModel` type,
for future use.

* Remove duplicate migration

* Remove another duplicate migration

* Add performance improvements from #22405 to ElementContainerPermissionService and add unit tests to prove it

* Fix element permission authorization for descendants

* Test for descendant element delete permissions before deleting an element container

* Update tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ElementPermissionServiceTests.cs

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
Co-authored-by: kjac <kja@umbraco.dk>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-05-06 11:30:52 +00:00
Andy ButlandandGitHub 179a3c8c5a Code Tidy: Clean up further obsoleted code scheduled for removal in Umbraco 18 (IFileService) (#22675)
* Remove the obsolete IFileService, the implementation and update all callers.

* Extend ServiceContext to include replacement service.

* Restore fallback behaviour for resolved users.

* Make TrySetTemplate async to avoid sync-over-async with new services.

* Addressed code review feedback.

* Reverted updates to stylesheet properties.

* Add helper and tests for path splitting.

* Ensure create of directory path on package data import.

* Verification with integration test.
2026-05-06 19:38:33 +09:00
Sven GeusensandGitHub d40eded264 Clarified BackOfficeTokenCookieSettings obsoletion message (#22727)
* Clarify obsoletion message

* Update obsoletion message with better templating/language
2026-05-06 10:29:35 +00:00
35fbc75f8d Typeloader: Comply with public obsoletion by making the Properties internal (#22726)
* Comply with public obsoletion by makng the Properties internal

* Tidied up XML header comments.

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Fixed indents.

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-06 09:54:03 +00:00
Andy Butland 626f0a9ee1 Bump version to 17.4.0-rc3. 2026-05-06 11:39:17 +02:00
Niels LyngsøandGitHub 212f3183c1 MD files for Design knowledge (#22725) 2026-05-06 09:26:28 +00:00
Niels Lyngsø 38c68ef384 Merge branch 'v17/hotfix/22472' 2026-05-06 10:39:09 +02:00
9671fec9ad Backoffice Mocks: Derive user language access from user groups (#22721)
fix(mocks): derive user language access from user groups

Previously hasAccessToAllLanguages was hardcoded to true and languages to
an empty array. Now both are derived from the user's user group memberships.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:29:53 +02:00
Andy ButlandandGitHub 489d9ebc2e File-system Services: Complete child scopes on read-miss and validation-failure paths (#22717)
* Ensure scopes in FolderServiceOperationBase are completed.

* Added integration tests to verify the fixes.
2026-05-06 13:32:39 +09:00
Lan Nguyen ThuyandNguyenThuyLan 417e63028d update custom property editor setup for acceptance test 2026-05-06 10:17:28 +07:00
Mads Rasmussen 9e34b76bf0 Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-05-05 22:29:56 +02:00
Mads Rasmussen a443f8ba08 manual revert of merge gone wrong 2026-05-05 22:29:35 +02:00
6789d7e757 fix(installer-user): added min length message for installer user elem… (#21829)
* fix(installer-user): added min length message for installer user element.

* Update src/Umbraco.Web.UI.Client/src/apps/installer/user/installer-user.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix password minlength message binding syntax

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Emma L Garland <1649855+emmagarland@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-05-05 22:26:40 +02:00
Mads Rasmussen daecbd02b8 Revert "Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS into claude/keen-nightingale-5ef5bd"
This reverts commit 0c57e304f8, reversing
changes made to 7c7073428d.
2026-05-05 22:12:39 +02:00
Mads Rasmussen 0c57e304f8 Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS into claude/keen-nightingale-5ef5bd 2026-05-05 22:10:55 +02:00
ede972f711 Radio button list: Not saving value on keyboard navigation (closes #22698) (#22699)
Fix radio button list not saving value on keyboard navigation

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-05-05 19:50:59 +00:00
Mads RasmussenandGitHub 2c88f2ae3c Current User: Fix reload not fetching fresh data when entity events fire (#22719)
* Ensure current-user reloads fetch fresh data

* Update current-user.context.test.ts
2026-05-05 21:32:35 +02:00
d40c959be7 Dashboard: Browser title + Hints (#22517)
* View Contexts for Dashboards + Section Views to support Browser Title and Hints

* fix code

* use alias for observe ctrl alias

* remove test code

* Position badge in section icon slot

---------

Co-authored-by: engjlr <enl@umbraco.dk>
2026-05-05 21:26:37 +02:00
77ded81eff Languages: Sort the global content language selector (closes #22628) (#22711)
* Align sorting of content language selector with variant selector.

* Hoist sortLanguages helpers to module scope.

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-05-05 18:33:07 +02:00
Sven GeusensandGitHub 34569e48f0 Update SupportsBlockLayoutAlias obsoletion timeframe (#22715) 2026-05-05 15:49:41 +00:00
2c9acb38f0 Management API: Override document-level security on AllowAnonymous endpoints (#22712)
* Management API: Override document-level security on AllowAnonymous endpoints

Operations on controllers/actions decorated with [AllowAnonymous] inherit the
document-level Bearer security requirement in OpenAPI 3.x unless they explicitly
declare an empty security array. Without that override, the generated SDK
attaches an Authorization: Bearer header to anonymous endpoints (server/status,
server/configuration, install/*, manifest/manifest/public, etc.), which forces
a /security/back-office/token refresh during the very first page load.

On v18/dev this manifests as a 500 from /server/status during a fresh install:
the Authorization header triggers OpenIddict, which resolves UmbracoDbContext
from DI, which throws because the connection string is empty in the install
state.

The transformer now sets operation.Security = [] on AllowAnonymous endpoints so
they correctly opt out of the document-level security. The committed OpenApi.json
and the regenerated sdk.gen.ts reflect this.

* Management API: Fix unit tests for AllowAnonymous security override

The transformer now sets operation.Security = [] (empty list) on
[AllowAnonymous] endpoints to override document-level security, instead
of leaving it null. Update the two affected tests to assert the new
behaviour and rename them to reflect that the transformer overrides
rather than skips security on anonymous operations.

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-05-05 15:17:38 +00:00
b3a9f86fe0 SignalR: Add configurable transport settings for load-balanced deployments without sticky sessions (#22700)
* WIP

* Cleanup and type generation

* Improve obsoletions

* Fix removed constructor

* Simplify logic because of SignalR's JS limitations

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Add SignalRSettings to Schema

* Abstrack SignalRRoutes class

* Fix bool to observable<bool>

* Refactor base class: pull down common service property, make abstract with protected constructor.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-05 14:51:45 +00:00
a50397f4e6 Elements: Clean up the remaining TODOs (#22689)
* Management API sweep

* Remove leftover comment from ContentService

* Clarify TODOs

* Use IPublishedElementCache instead of IElementCacheService in ElementPickerValueConverter

* Rename private helper for clarification

* Fix build error

* Remove "Create" from ElementService, as it was only ever used for tests

* Rename DocumentVariantStateModel to PublishableVariantStateModel in backoffice client

Refresh OpenApi.json and regenerate backend-api after the server-side enum rename, then update all client imports and usages to match.

* Client: Aliased `PublishableVariantStateModel` for each module package

* Client: Resolve circular dependencies for variant-state alias

Hoist the `UmbDocumentVariantState` and `UmbElementVariantState` aliases (re-exporting `PublishableVariantStateModel`) into dedicated `variant-state.ts` files. Internal modules now import the alias from this leaf file instead of the package's root `index.js`, breaking the 5 cycles reported by `npm run check:circular` while keeping the public API surface unchanged.

* Post-merge fixes

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-05-05 16:40:14 +02:00
c7ba6506aa E2E: QA Updated acceptance tests to reflect UI changes in v18 (#22709)
* Updated webhook tests since Change the default payload type to "minimal"

* Added .skip tag for block grid area tests due to the actual issues

* Update template tests due to test helpers changes

* Updated locator for rollback button due to UI changes

* Updated locator for block edit button due to UI changes

* Updated locator for delete block icon

---------

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-05-05 14:38:59 +00:00
Laura NetoandGitHub 96ae2f384f Delivery API: Drop $type discriminator from response payloads (#22710)
* Delivery API: Drop $type discriminator from response payloads

Removed [JsonDerivedType] from IApiContent and IApiContentResponse so
System.Text.Json stops emitting $type on collection endpoints and the
OpenAPI spec stops requiring a discriminator on the generic schemas,
restoring v17 behaviour. Consumers that need polymorphic responses can
still register derived types via ContentJsonTypeResolverBase.

Snapshot regenerated.

* Delivery API: Preserve cultures property order on collection responses

Added [JsonPropertyOrder(100)] to IApiContentResponse.Cultures so the
property is serialized last when the static type is the interface
(collection endpoints), matching the existing attribute on the concrete
ApiContentResponse class. Mirrors the [JsonPropertyOrder(-100)] pattern
already used for ContentType on IApiElement / ApiElement.

Snapshot regenerated.
2026-05-05 15:37:22 +02:00
f158e6601b Code Tidy: Remove unused obsoleted InstalledPackage mapping (#22713)
* Remove unused obseleted InstalledPackage mapping

* Fix up XML header documentation on PackageViewModelMapDefinition.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-05 12:18:25 +00:00
8e6e0e7f05 Code Tidy: Clean up further obsoleted code scheduled for removal in Umbraco 18 (ILocalizationService) (#22677)
* Remove the obsolete ILocalizationService and implementation and update all callers to non-obsolete alternatives.

* Addressed code review feedback.

* Fixed failing integration test.

---------

Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
2026-05-05 11:50:45 +00:00
Jacob Overgaard d0648ac7df chore: updates references to renamed uui-css.css -> light.css file 2026-05-05 13:31:11 +02:00
Andy ButlandandGitHub c7d055a6e2 Caching: Invalidate published content type cache for element types (#22704)
* Ensure content type cache is correctly invalidated for element types.

* Clear key to Id map on clear all.

* Refactor and update tests for additional coverage and naming alignment.

* Updates from code review.
2026-05-05 13:20:37 +02:00
c257b91443 Code Tidy: Make name non-nullable on content/element/media/member constructors (#22638)
* Remove overloads for creation of content that allow for null name.

* Add defensive null guard on create media.

* Remove unused publishedValueFallback parameter in published content models.

* Fixed failing integration tests.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-05-05 12:10:47 +02:00
Laura NetoandGitHub 6866a964f6 Elements: Add elements to the backoffice global search (#22674)
* Backoffice Element Search: add global search provider for elements

Adds an "Elements" category to the backoffice global search, scoped to
the Library section.

Server: SearchElementItemController exposes
  GET /umbraco/management/api/v1/item/element/search
backed by IEntitySearchService (DB-backed name match, mirrors the
DataType search pattern). Maps results via IElementPresentationFactory.

Client: new src/packages/elements/search/ module with a search provider,
repository, server data source, search-result-item element, and
globalSearch manifest (alias Umb.GlobalSearch.Element). Wired into the
elements package manifests. Backend SDK regenerated from OpenApi.json.

* Backoffice Element Search: surface ancestors, trashed and draft state

- New ancestors endpoint at /item/element/ancestors so result items can
  render a parent breadcrumb (uses NamedItemResponseModel to cover
  element folder ancestors).
- ElementItemResponseModel.IsTrashed added and populated by the
  presentation factory, flowing through search and item responses.
- Frontend search result item renders breadcrumb, Trashed tag with
  strike-through, and Draft tag (mirrors document search result item).

* Address PR review feedback

- Add integration test for AncestorsElementItemController (mirrors
  AncestorsDocumentItemControllerTests).
- UmbElementSearchItemModel: declare `name: string` (the search result
  contract requires it; mirrors UmbDocumentSearchItemModel).
- Element search data source: drop the empty-string fallback on `name`
  and add the same TODO comment used in the document data source.
- Add JSDoc to UmbElementSearchProvider, UmbElementSearchRepository and
  UmbElementSearchServerDataSource (matches document equivalents).

* Backoffice Element Search: export search consts and unblock isTrashed on item endpoint

- Re-export ./search/constants.js from the elements package barrel so
  UMB_ELEMENT_SEARCH_PROVIDER_ALIAS and UMB_ELEMENT_GLOBAL_SEARCH_ALIAS
  are reachable as the export-consts test expects.
- element-item.server.data-source.ts: stop hardcoding isTrashed to false
  - now that ElementItemResponseModel exposes the flag, item-based UIs
  reflect the actual trashed state.
2026-05-05 10:08:37 +00:00
Andy ButlandandGitHub 233865a1e6 Code Tidy: Clean up obsoleted code scheduled for removal in Umbraco 18 (IDomainService, IContentTypeBaseService) (#22629)
* Fix naming warning in UmbracoIntegrationTestBase.

* Fixes a namespace.

* Removed TODO for removing registrations of UserPasswordConfigurationSettings and MemberPasswordConfigurationSettings. The inheritance hierarchy of UmbracoUserManager makes this difficult and unnecessary to unpick.

* Aligned TODO with obsoletion message.

* Remove obsoleted code from IDomainService and update all callers.

* Removed obsolete members from IContentTypeBaseService.

* Addressed code review feedback.

* Fix Setup on ThreadSafetyTests.
2026-05-05 10:02:18 +00:00
877e93aec2 Elements: Add the Library section to the admin group on upgrade (#22706)
* Add the Elements section to the admin group on upgrade

* Update src/Umbraco.Infrastructure/Migrations/Upgrade/V_18_0_0/AddElementSectionForAdmins.cs

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-05-05 09:58:19 +00:00
9e930739fb Tags: Close suggestion dropdown on blur and escape (closes #22636) (#22650)
* Close suggestion dropdown on blur and escape, fix suggestion selection

* Fix code complex

* Fix to tab and complexity

* Fix to tab and complexity

* Fix to tab and complexity

* Clear matches on add/escape and remove focus rule

---------

Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-05-05 09:39:41 +00:00
727581b88b State System: more tests, MD updates and a tiny bit more consistency (#22673)
* unit test for boolean state

* improve umb class state set value identical check

* consistent ability to make a observablePart

Co-authored-by: Copilot <copilot@github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
2026-05-05 09:33:24 +00:00
b49929af97 Backoffice: Introduce Value Type and Value Summary extensions (#22481)
* Add table collection view and manifests

* Use table kind in collection example

* Update entity-name-table-column-layout.element.ts

* Recompute table rows when item hrefs change

* define and render columns from manifest

* wip language implementation

* map to unique field

* rename to label

* test implementation for users table

* experiment: value minimal display extension

* register as workspace context

* add boolean display

* clean up

* add example entity actions

* add example description

* Update table-collection-view.element.ts

* Omit base 'meta' and relax table meta type

* Hardcode description column when present

* localize column names

* Update table-collection-view.element.ts

* Type manifest on collection view elements

* Use UmbLitElement instead of LitElement

* fix types

* Update entity-name-table-column-layout.element.ts

* provide entity context for each table row

* fix breaking change and introduce a deprecation warning

* Add status column to example collection view + localize column labels

* implement the UmbTableColumnLayoutElement interface

* add tests for the table collection view

* Make host element optional; add table docs/types

* Update controller-host.mixin.ts

* Update src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-table-column-view/entity-actions-table-column-view.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add language collection context

* introduction of value type and rename to value summary

* Add core DateTime value summary; migrate user last-login

* remove unused

* Rename user group value type to References

* Remove the component's standalone resolution path

* Add start-node value summaries & sections for user group table

* Guard resolver and render when start node missing

* refactor value-summary resolver, coordinator, and API

* introduce default kind

* remove $ in variable name

* make extension element name more specific to not collide with interface name

* add element base

* move to section module

* return as observable from resolver

* use extension item repository

* prefix start node feature with user

* add value type and value summary for date-time-with-time-zone property editor

* render timezone

* Add fallback render if no extensions can be found

* Add color-picker value summary and types

* add summary for slider + align types

* make manifest prop name more explicit

* align element name with class name

* reorganize

* manually combine imports to decrease the number of dynamic imports

* export as valueResolver instead of api

* Inline default value-summary kind manifest

* Use single raw value in value-summary coordinator

* Render summaries on Document Collection cards

* format date the same way as the property editor

* first iteration of docs and skills

* updates to docs + skills

* render icon for language collection items

* remove test collection manifest

* delete local language table collection view implementation

* implement the get hrefs method in the user group collection context

* Update controller-host.mixin.ts

* Update entity-name-table-column-layout.element.ts

* Update entity-actions-table-column-view.element.ts

* Handle undefined row element in table rendering

Allow onRowRendered to accept an undefined element and clean up row contexts when a row is unmounted. Update the callback signature in table.element.ts and handle the undefined case in table-collection-view.element.ts by destroying the host and removing the stored context for the item to avoid memory leaks when rows are removed.

* Update controller-host.mixin.ts

* remove test registration

* Prefix type in value key generation

* Skip render when boolean value is undefined

* Add JSDoc and reorder imports in coordinator

* fix lint errors

* Update icons.ts

* valueResolver to class in tests

* Update index.ts

* Add value-summary and value-type Vite entries

* Cache table config and column cell elements

* Use localization for user state labels

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-05-05 09:07:39 +00:00
Niels Lyngsø adf02910ab Merge branch 'main' into v18/dev 2026-05-05 10:30:57 +02:00
984838433c MD: improve knowledge on get vs consume context (#22676)
* improve Md regarding get vs consume context

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-05 10:14:33 +02:00
Niels Lyngsø 89e89a38ab add library package 2026-05-05 09:56:47 +02:00
Niels Lyngsø fa123444bd re-introduce element package 2026-05-05 09:48:59 +02:00
Niels Lyngsø 5833269196 Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.element.ts
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/ConstantHelper.ts
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/ContentUiHelper.ts
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/UserApiHelper.ts
2026-05-05 09:24:02 +02:00
Andy ButlandandGitHub 0c9b817372 Code Tidy: Clean up obsoleted code scheduled for removal in Umbraco 18 (IDataTypeService) (#22634)
* Remove obsolete methods from IDataTypeService and update callers.

* Fixed failing integration test and resolved code review feedback.

* Further code review feedback.

* Introduce shared helper for retrieving data type from property type.
2026-05-05 05:06:50 +00:00
Andreas Lykke BorgandGitHub cf2b519ff9 Accessibility: Added missing labels to add property and create new collection (#22701)
Add missing label attributes to form controls
2026-05-05 07:02:52 +02:00
Sven GeusensandGitHub 29ecd48cc1 Migrations: Removed obsoleted MigrationBase and all migrations between old and current LTS (13-17) (#22618)
* Change AddElements to a premigration

* Move AddAllowedInLibraryToContentType to premigration

* Remove old migrations and remove obsoleted migratiobase

Includes updating existing migrations and tests to AsyncMigrationBase

* Update claude files

* update xml comment

* Set correct initalstate

* More cleanup

* Remove old migration tests

* Put the test ignore on the right testcase 🙈

* cleanup async migrateasync calls without awaits in tests

* Updated InitialStateVersion
2026-05-05 06:48:16 +02:00
Andy ButlandandGitHub 6c2473aeb0 Code Tidy: Remove package validation suppression files (#22696)
Removed CompatibilitySuppressions.xml files.
2026-05-05 10:14:10 +09:00
Andy ButlandandGitHub 7e2edd4733 Dependencies: Bump selected NuGet packages to latest versions (#22693)
* Bumped selected dependencies to the latest versions.

* Resolved warning seen on dotnet restore.
2026-05-05 09:09:00 +09:00
Laura NetoandGitHub 0d6aedac7c Management API: Refactor element tree controllers to use start node filter service (#22598)
* Refactor element tree controllers to use start node filter service

Move user start node filtering logic from UserStartNodeFolderTreeControllerBase
and ElementTreeControllerBase into a dedicated ElementStartNodeTreeFilterService,
matching the pattern established for document and media trees in PR #22486.

Add a virtual TreeObjectTypes property to UserStartNodeTreeFilterService so
element trees can query both Element and ElementContainer object types.

* Address PR review feedback

* Apply PR review feedback

Replace TreeObjectType (singular) with abstract TreeObjectTypes (array).
Use static readonly arrays in concrete implementations to avoid
allocations.

Move multi-object-type test into UserStartNodeTreeFilterServiceTests
since it exercises base class behavior, not the element service
specifically.
2026-05-04 23:13:23 +02:00
Andy Butland a773ba168b Merge branch 'release/17.4.0' 2026-05-04 23:00:48 +02:00
Andy ButlandandClaude Opus 4.7 cd406fba43 Remove npm/docs manual approval gates, keep MyGet-cascade fix.
The manual approval gates added for the duplicate-version rerun were
single-use scaffolding for that specific release. Remove them and
tighten Deploy_Npm and Upload_API_Docs to require Deploy_NuGet to
have actually succeeded (Succeeded or SucceededWithIssues) — so a
NuGet failure deliberately blocks the npm release and docs upload.

Keep the structural change to inspect dependencies.Deploy_NuGet.result
directly rather than rely on the transitive succeeded(). That fix is
permanent: it's what protects npm and docs from cascade-skipping
whenever MyGet has another upstream outage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 21:26:25 +02:00
Andy ButlandandClaude Opus 4.7 caeb354064 Allow npm release and API docs upload to run when MyGet or NuGet fails.
Both stages used implicit succeeded(), which is transitive across the
full ancestor graph. A MyGet failure (or a NuGet failure on a re-run
where the version is already published) would therefore cascade-skip
both stages even though their own work is independent of those feeds.

Switch them to inspect dependencies.Deploy_NuGet.result directly so
they remain eligible when NuGet ran and either succeeded or failed,
while still being skipped when Deploy_NuGet itself was Skipped (e.g.
non-release runs). Upload_API_Docs additionally requires Build_Docs
to have produced artifacts.

Add a manual approval gate (ManualValidation@0 server job) to each
stage so a NuGet failure caused by something genuinely unrecoverable
(e.g. expired API key) doesn't auto-promote npm or docs publishes -
the operator must explicitly approve each downstream stage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:19:53 +02:00
Engiber LozadaandGitHub 8f6bb64ced Content Workspace: Add variant sync when switching app culture (closes #16853) (#22566)
* Sync workspace URL on language change

* Use template literals for workspace paths

* Move and improve culture URL sync logic
2026-05-04 17:01:24 +00:00
dec99737b7 Build pipeline: Add manual approval gate to NuGet release (#22695)
* Add manual deploy to NuGet for when MyGet publish fails.

* Simplified instructions for manual approval.

* Gate NuGet release on MyGet's direct result, not transitive succeeded/failed.

succeeded() and failed() are transitive across the full ancestor graph,
so a failure in Unit/Integration/E2E (which skips Deploy_MyGet) still made
or(succeeded(), failed()) evaluate to true and opened the approval gate
on a broken build. Inspect dependencies.Deploy_MyGet.result instead so
Deploy_NuGet only becomes eligible when MyGet itself actually ran.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 18:43:09 +02:00
7eb586f520 Code Tidy: Clean up further obsoleted code scheduled for removal in Umbraco 18 (IMemberService.GetMembersByPropertyValue) (#22678)
Removed obsolete methods on IMemberService, their implementations and the related tests.

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-05-04 14:59:49 +00:00
Andy ButlandandGitHub 138e29db58 Code Tidy: Remove obsolete code scheduled for removal in Umbraco 18 (UmbracoApiController and front-end API auto-routing) (#22692)
* Remove UmbracoApiController and associated code.

* Test naming and attributes.
2026-05-04 16:13:22 +02:00
Andy ButlandandGitHub 1a87feb84d Code Tidy: Remove obsolete code scheduled for removal in Umbraco 18 (UrlSegment extension method) (#22682)
* Remove obsolete UrlSegment extension methods and update callers. Clarify obsoletion of UrlSegment property for Umbraco 19.

* Use 20 for the new obsoletions.

* Align all existing obsolete and non-obsolete calls to retrieve a URL segment to use IDocumentUrlService.

* Fix failing tests.

* Revert incorrectly updated obsoletion removal version.
2026-05-04 13:36:58 +00:00
Niels LyngsøandGitHub 4e7bf3c483 Validation: Data lookup mismatch for JSON Path Queries (#22609)
* unit tests to prove issue

* ensure full match for json path filter query

* check for null value

* remove comment

* remove comment

* remove comment
2026-05-04 15:02:39 +02:00
7136e12e54 Property Editor UI Picker: Implement fuzzy search (#22468)
* extend icons with information from theseaurus

* implement new icon search logic

* clean-up data

* sorting with a backup of the name

* refactor into a controller

* improve multi word group search

* embed lucide data

* rename tech into technology

* remove paper from dollar

* implement fuzzy search for property editor UIs

* minor style update

* improve property editor UI search

* improve search

* improve search data for Property Editor UIs

* remove alias search from property editor ui search

* add usage keywords

* Property editor Suggestions based on Property Label

* related should not show up in search

* rename to suggestionQuery

* update threshold

* separate name words

* also consider full icon name match

* better comment

* other approach for full name matches

* full icon name search if query contains a -

* fix test

* cache all tokens as well

* catch rejection

* resolve feedback

* handle rejected promise

* cancel debounce on disconnect

Co-authored-by: Copilot <copilot@github.com>

* declare voids

* corrections

Co-authored-by: Copilot <copilot@github.com>

* back out if no tokens

---------

Co-authored-by: Copilot <copilot@github.com>
2026-05-04 12:28:25 +00:00
2434c3ec7b Global Elements: Implements auditLog and contentRollback kinds for History and Rollback (#22633)
* Implements `auditLog` kind for Elements

* Implements `contentRollback` kind for Elements

* Adds JSDoc comments to element rollback repository and data source

* Exports `UMB_ELEMENT_AUDIT_LOG_REPOSITORY_ALIAS` from `@umbraco-cms/backoffice/element`

Surfaces the constant through the element audit-log barrel so it's available on the public package entry, matching the documents audit-log pattern.

* Added `rollbackNotificationMessage` for Element Rollback

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-05-04 12:20:10 +00:00
Nicklas KramerandGitHub f1f215a3a8 User management: Improved error message when deleting active user (closes #22669) (#22687)
* Adding a more detailed error message when deleting a logged in user

* Fixing overlooked integration test

* Fixing enum binary mistake. Appending enum to the end rather than in the middle.

* Introducing better naming for the enum
2026-05-04 12:12:07 +00:00
Niels LyngsøandGitHub 7e675e243b Claude MD: Code Comments (#22690)
* initial commit

* improve docs
2026-05-04 11:45:55 +00:00
5bd0b720a0 Document picker: show ancestor breadcrumb path in document picker search results (closes #22645) (#22649)
* Show ancestor breadcrumb path in RTE picker search results

* hide tree when searching

* use clear localization instead of delete

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-05-04 11:36:40 +00:00
c725881e67 Elements: Published element extensions (#22585)
* Add element-level extension methods for variance, culture, fallback support

Published Element Extensions now support the same culture, type-checking,
equality, and creator/writer methods that were previously only available
on Published Content Extensions. Content extensions delegate to the
element versions, preserving backwards compatibility.

New element extensions (Core):
- HasCulture, IsInvariantOrHasCulture, CultureDate
- IsDocumentType (both overloads)
- IsEqual, IsNotEqual
- GetCreatorName, GetWriterName
- HasValue with IPublishedValueFallback and Fallback support

New friendly element wrappers (Web.Common):
- Name, CultureDate, CreatorName, WriterName

New non-friendly element extensions (Web.Common):
- CreatorName, WriterName (with IUserService parameter)

* Add unit tests for PublishedElement extension methods

Tests for core extensions (HasCulture, IsInvariantOrHasCulture,
CultureDate, IsDocumentType, IsEqual/IsNotEqual, GetCreatorName,
GetWriterName, HasValue with fallback) and friendly wrappers (Name,
CultureDate, CreatorName, WriterName). All mocks use MockBehavior.Strict.

* Fix empty XML doc param tag for variationContextAccessor in CultureDate

* Delegate content CreatorName/WriterName to element friendly extensions, remove redundant UserService field

* Address PR review: restore StaticServiceProvider in TearDown, use case-insensitive culture dictionary in tests

* Add remarks note about Fallback.ToAncestors not being supported at element level

* Clarify the casting for readability

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-05-04 13:30:27 +02:00
Andy Butland 51892a840c Merge branch 'v18/dev' of https://github.com/umbraco/Umbraco-CMS into v18/dev 2026-05-04 13:15:20 +02:00
Andy Butland a2fa694553 Merge remote-tracking branch 'origin/main' into v18/dev 2026-05-04 13:15:00 +02:00
Nhu DinhandGitHub 1215d83b0f E2E: QA Added acceptance tests for backoffice login, logout and reset password (#22635)
* Added api helper for reset auth state

* Added more constant variables for login and forgot password message

* Added ui helper for login page

* Added api helper for smtp

* Added tests for backoffice login

* Added tests for backoffice logout

* Added tests for forgot password

* Added api helper for user

* Make tests run in the pipeline

* Updated appsetting to enable reset password

* Added more waits

* Added waits

* Updated locator

* Fix flaky tests

* Updated confirmation message

* Fixed comments

* Removed unused code

* Reverted npm command
2026-05-04 10:30:27 +00:00
349e9d1130 Blueprints: Fix intermittent blank workspace when creating documents from blueprints (closes #21996) (#22422)
* Resolve blank workspace when creating documents from blueprints.

* Addressed code review feedback.

* Revert defensive fixes that don't appear to contribute to fixing the bug.

* remove comment

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-05-04 10:28:03 +00:00
Laura NetoandGitHub 4e74e33dde Templates: Update Umbraco extension template for OpenAPI route changes (#22670)
* Update Umbraco extension template for OpenAPI route changes

Following the migration from Swashbuckle to Microsoft.AspNetCore.OpenApi
in #21058, the extension template still pointed at the old Swagger URL
pattern and used outdated terminology in code comments.

- generate-client npm script now points at /umbraco/openapi/{name}.json
  instead of /umbraco/swagger/{name}/swagger.json
- generate-openapi.js renames swaggerUrl to openApiUrl and updates the
  example URL in the missing-argument error message
- UmbracoExtensionApiComposer.cs comments updated from "Swagger" to
  "OpenAPI"

* Scope custom OpenAPI document to extension's own endpoints

Without an explicit ShouldInclude predicate, Microsoft.AspNetCore.OpenApi
only includes endpoints whose ApiExplorer GroupName equals the document
name. The template's controller declared a different group name, so the
custom document was created but stayed empty (paths: []), which in turn
made npm run generate-client produce an empty TypeScript SDK.

Filter by the [MapToApi] attribute already present on the extension's
controller base, mirroring the pattern used by the Management and
Delivery API options.

* Add Microsoft.AspNetCore.OpenApi reference to Central package management

The PerProject mode of the umbraco-extension template took a direct
dependency on Microsoft.AspNetCore.OpenApi (with a long comment
explaining why) but the Central mode did not, so default Central
scaffolds failed to build with the source-generator interceptors
error. Mirror the dependency in the Central csproj block and
Directory.Packages.props.
2026-05-04 12:16:48 +02:00
2d4418b36f Code Tidy: Clean up further obsoleted code scheduled for removal in Umbraco 18 (LogFiles, legacy permissions tables, LoggerConfigExtensions) (#22679)
* Remove obsolete logger configuration extensions.

* Removed obsolete database table DTO and constants.

* Removed obsolete LogFiles constant.

* Moved SuperUserId constants obsoletion to 19.

* Remove further reference to removed table.

* Comment out reference to removed table in migration that is also for removal for 18.

* Remove further obsolete methods from LoggerConfigExtensions

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-04 12:08:16 +02:00
Niels LyngsøandGitHub bbebb07e8c Blueprints: Fix creating documents from blueprints (closes #21996) (#22688)
cherry picked fix from #22422
2026-05-04 10:03:31 +00:00
0eef8e6b31 Code Quality: Add ModelState validation to BackOfficeLoginController (#22681)
* Add ModelState.IsValid validation in controller action

* Update method documentation and return simple BadRequest response (aligns with other usages, e.g. BackOfficeController.Verify2FACode).

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-04 09:44:50 +00:00
f2dc9e7031 Block permissions: Correction of read-only inheritance and language access (#22522)
* remove inheritance of readonly state

* keep rendering edit in read-only mode

* INVARIANT variant id as static

* parse readonly state, without variant ids as origin is the property read-only state

* stop inheriting read only

* no need for async

* setup read only state based on user permissions

* simplify document-block-property-level-permissions

* make isPermittedForObservableVariant return undefined in bad case

* revert

* improve life cycle for extension initializer

* fix and clean-up

* clean up

* unit test for the actual problem

* clean up

* clean up

* revert logic

* transform access context into local controller

* re-introduce submit create button

* simplify match

* update js docs

* strict compare on config object level, to cover multiple conditions of the same alias.

* Revert "transform access context into local controller"

This reverts commit 1a83d9586b.

* rename file in manifest

* RTE: set manager readOnly

* set fallback on readOnly

* inherit readOnly state when block workspace is invariant

* read-only tag for Block Workspace

* make guard fallback reactive

* observe readOnly languages

* no if sentence

* observe fallback for property + name guards

* prevent cancelled context get to cause problems

* revert removal of  || this._isReadOnly check for component rendering

* add comment for clarification

* remove style import

* mark as readonly and make js-const

* remove `as const`

* unit test for reactive fallback feature

* more guard unit tests

* more variantId tests

* move block language access controller to block package

* Update base-extension-initializer.controller.ts

* fix test

* improve switch condition

* offset condition

* Block Workspace: Add data-mark for acceptance test locator

* apply entity-type to the workspace data-mark

* layout-headline

* Updated locator to use new data-mark

* Updated tests to make them less fragile

* null ctrl alias for constructor initiated observations

* import directly

* do not react to not existing user-data or missing context

* add comment

* refactor package registration logic

* package name for code editor

* leave unregistere out

* await load all bundles

Co-authored-by: Copilot <copilot@github.com>

* move initializer to app element

* Batch register extensions with validation

* remove await on load for extension initializers

* Debounce extension updates and set loaded flag

* remove unused imports

* refactor backoffice -> app

* clean up imports

* rename comment

Co-authored-by: Copilot <copilot@github.com>

* base extension initializer is loaded update

* app loader

Co-authored-by: Copilot <copilot@github.com>

* embed umbraco-packages

* remove lazy loads from dataSourceDataMapper

* revert

* enable routes to be undefined

Co-authored-by: Copilot <copilot@github.com>

* comment

Co-authored-by: Copilot <copilot@github.com>

* make sure load only calls once

Co-authored-by: Copilot <copilot@github.com>

* comments and todos

* destroy consumer if existing

* block language access tests

* load user at the end of loading all package modules

* assign symbol for is-trashed observer

* revert language readonly rules

Co-authored-by: Copilot <copilot@github.com>

* is-trashed context + observation

Co-authored-by: Copilot <copilot@github.com>

* read-only as view prop for block list

Co-authored-by: Copilot <copilot@github.com>

* readonly as view prop

* readonly prop for grid,rte,single

Co-authored-by: Copilot <copilot@github.com>

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Andreas Zerbst <andr317c@live.dk>
Co-authored-by: Copilot <copilot@github.com>
2026-05-04 09:40:34 +00:00
fe413cd0ae Document Type Workspace: Hide non-applicable settings when Document Type is configured as Element Type (#22388)
* Avoid render structure view when element type is active

* Avoid render history clean up when is an element type

* Replace hidden sections with inline "not applicable" message for Element Types

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-05-04 09:26:17 +00:00
Nhu DinhandGitHub b638fa0c73 E2E: Revert npm command for smokeTest (#22683)
* Revert npm command for smokeTest

* Updated audit trail for trash content
2026-05-04 15:48:20 +07:00
6ce2ab9fe9 HttpClients: Deprecate unused HttpClient registered with certificate validation bypass (#22684)
Mark HttpClient IgnoreCertificateErrors as obsolete due to security risk and add TODO to remove in a future release

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-05-04 10:32:11 +02:00
Andy Butland 5e1aabcce6 Bump version to 17.4.0-rc2. 2026-05-04 10:15:16 +02:00
8d961b1873 Blocks: Adds blockAction extension type (#22459)
* feat(block): add blockAction extension type for extensible block entry actions

Introduce a new `blockAction` extension type that allows both internal and
3rd-party extensions to register actions on block items. This replaces the
hardcoded Delete button on Block List entries with an extension-registered
action, while keeping Edit Content, Edit Settings, and Copy to Clipboard
as slotted content for incremental migration.

The new `<umb-block-action-list>` element owns the `<uui-action-bar>` and
renders a `<slot>` for hardcoded actions followed by extension-registered
`blockAction` extensions, enabling one-by-one migration of actions.

* feat(block): apply blockAction extension to grid, rte, and single block editors

Extend the blockAction pattern to all remaining block entry elements.
Each editor now uses <umb-block-action-list> with slotted hardcoded
actions and the Delete action registered via the extension registry.

* fix(block): render blockAction extensions directly in uui-action-bar

Replace umb-extension-with-api-slot with UmbExtensionsElementAndApiInitializer
to render blockAction elements as direct children of uui-action-bar. This fixes
the border-radius issue where the wrapper element broke :first-child/:last-child
structural selectors used by uui-action-bar for button styling.

* refactor(block): replace showOnReadOnly meta with BlockEntryIsReadOnly condition

Add a new Umb.Condition.BlockEntryIsReadOnly condition that checks the
read-only state from UMB_BLOCK_ENTRY_CONTEXT. This replaces the inline
read-only guard and showOnReadOnly meta flag on the default kind element.

Delete action uses the condition with match: false (hidden when read-only).
Copy to Clipboard has no condition (always visible). 3rd-party actions
opt in to read-only gating by adding the condition to their manifest.

* feat(block): migrate clipboard copy to blockAction extension

Move the Copy to Clipboard action from hardcoded buttons to a registered
blockAction extension across all four block editors. The copy logic is
moved from each entry element into its respective entry context, with a
base copyToClipboard() method on UmbBlockEntryContext.

* docs(block): add plan for migrating Edit Content and Edit Settings to blockAction

* feat(block): migrate Edit Settings to blockAction extension

Replace the hardcoded Edit Settings button with a blockAction extension
using the default kind. The API class provides getHref() for workspace
navigation and getValidationDataPath() for the invalid badge.

Adds getValidationDataPath() to the UmbBlockAction interface and default
kind element, enabling any blockAction to display a validation badge.

Introduces Umb.Condition.BlockEntryHasSettings condition to control
visibility based on whether the block has a settings element type.

* feat(block): migrate Edit Content to blockAction extensions

Split the hardcoded Edit Content button into two blockAction extensions
controlled by manifest conditions:

- Umb.BlockAction.EditContent — navigates to workspace content view,
  shows validation badge via getValidationDataPath()
- Umb.BlockAction.ExposeContent — calls context.expose() when block
  is not yet exposed and content edit is hidden

Adds match support to BlockEntryShowContentEdit condition and creates
a new BlockEntryIsExposed condition at the entry level.

Removes the <slot> from umb-block-action-list — all block entry actions
are now fully driven by the extension registry.

* Removes plan/spec files

* chore(block): address review findings for blockAction feature

- Add TODO comment for stale getHref/getValidationDataPath (I-1)
- Remove orphaned @state() properties from all four entry elements (I-2)
- Add UMB_BLOCK_ENTRY_SHOW_CONTENT_EDIT_CONDITION_ALIAS constant and
  replace string literals in edit-content/expose-content manifests (I-3)
- Change Expose Content weight from 400 to 399 (S-1)
- Add JSDoc to exported types and classes (S-2)
- Fix condition import alias — rename workspace-level to
  UmbBlockWorkspaceIsExposedCondition (S-3)

* fix(block): revert CSS custom property rename to preserve backwards compatibility

Restore the original per-editor CSS custom property names:
--umb-block-list-entry-actions-opacity, --umb-block-grid-entry-actions-opacity,
--umb-block-single-entry-actions-opacity. The action bar opacity styles are
now back in each entry element (using #actions selector), so the unified
property name is no longer needed.

* fix(block): address PR review feedback from Copilot and Claude bots

- Fix Expose button label regression — replace dynamic
  '#blockEditor_createThisFor' (function key) with static '#actions_create'
  so the button no longer renders "Create undefined"
- Guard empty-string href in EditContent and EditSettings actions —
  'workspaceEdit{Content,Settings}Path' emits '' before ready; return
  undefined instead of '' so the button doesn't get href="" (which would
  navigate to the base URL on click)
- Clear _href in default kind api setter — prevents stale href when the
  api is replaced or set to undefined
- Fix barrel imports in 3 block entry conditions — import
  UMB_BLOCK_ENTRY_CONTEXT directly from context-token.js rather than via
  the ../index.js barrel, reducing circular dependency risk
- Make block-action-list reactive to contentTypeAlias changes — the
  extensions initializer is now re-created when unique or
  contentTypeAlias changes, so forContentTypeAlias filters apply
  correctly when contentTypeAlias resolves asynchronously
- Throw in base copyToClipboard() — the default no-op on
  UmbBlockEntryContext now throws rather than logging a warning, so any
  future subclass that fails to override fails visibly

Tests for the new conditions were attempted but deferred to follow-up;
context observable mocking semantics need more investigation.

* fix(block): restore uui-action-bar styling on block-action buttons

Remove the `compact` attribute from the inner `<uui-button>` and bridge
the CSS custom properties set by `uui-action-bar::slotted(*:first-child)`
etc. through `<umb-block-action>`'s shadow DOM via intermediate
`--umb-button-*` variables. Without this bridge, `uui-button`'s own
`:host` declarations shadow the inherited values and the first/last
button border-radius + padding don't apply.

* fix(block): address second-pass PR review feedback

- Throw when RTE editor manifest is missing so clipboard entries are
  never written with an empty propertyEditorUiAlias (would silently
  fail to match on paste)
- Replace bare `return` with `return nothing` in default kind element
  render() for type-level clarity
- Add class-level JSDoc to exported block action classes
  (UmbEditContentBlockAction, UmbEditSettingsBlockAction,
  UmbDeleteBlockAction, UmbCopyToClipboardBlockAction,
  UmbExposeContentBlockAction) and UmbBlockActionDefaultElement

* refactor(block): reduce copyToClipboard complexity per CodeScene feedback

Extract `#buildPropertyValue()` helper in List, RTE, and Single entry
contexts to move the four content/layout/settings/expose ternaries out
of copyToClipboard, lowering its cyclomatic complexity.

Split the compound `||` context guards into sequential early-return
checks so each missing context throws with a specific error message,
and the "Complex Conditional" smell is removed.

* refactor(block): further reduce RTE copyToClipboard complexity

Consolidate three sequential `await getContext(...)` calls into a single
`Promise.all`, dropping the cyclomatic complexity below CodeScene's
threshold of 9.

* refactor(block): extract RTE clipboard write into helper method

Split the post-guard write phase into `#writeClipboardEntry` to bring
both methods well under CodeScene's cyclomatic complexity threshold.

* clean up action

Co-authored-by: Copilot <copilot@github.com>

* show edit content / settings despite read-only state

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Copilot <copilot@github.com>
2026-05-04 08:07:16 +00:00
101acdd583 Templates: Rename "Master Template" to "Layout Template" (#21743)
* Rename "Master Template" to "Layout Template" throughout the codebase

Since Umbraco switched from WebForms to MVC, the "Master" template
terminology has been incorrect — in Razor/MVC the parent template is
called a "Layout", not a "Master page". This renames the concept across
C# models, services, repositories, the Management API, and the
backoffice frontend while preserving backward compatibility via
[Obsolete] members scheduled for removal in Umbraco 20.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove dead template layout XML element code and rename test methods

The serializer code that wrote <Master>/<MasterAlias> elements was never
executed because Lazy<int>.IsValueCreated was always false after loading
from the database. The corresponding import code that read these elements
was equally dead since no package.xml ever contained them. Template
parent-child hierarchy is resolved from Razor Layout directives instead.

Also renames 4 test methods from "Master" to "Layout" to match the
updated terminology.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Packaging: Suppress noisy log when imported Template has no Layout

A null Layout is legitimate for root layout files (e.g. `Layout = null;`)
and shouldn't be reported as "invalid". Only log when a non-null Layout
was referenced but couldn't be resolved in the import.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update acceptance tests and further references in comments.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Sebastiaan Janssen <sebastiaan@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-04 10:01:42 +02:00
Lee KelleherandGitHub ad904d6b05 Global Elements: Localize bulk publish/unpublish notifications (#22641)
* Localizes element bulk publish/unpublish notifications

* Removed the "visible on the website" part from localizations for Elements.
2026-05-04 04:35:30 +00:00
Andy ButlandandGitHub 013d55ef30 Routing: Ensure IPublishedContent.UrlSegment respects umbracoUrlName (closes #22655) (#22663)
* Align obsolete UrlSegment with result of replacement service call.

* Resolved warnings in tests.

* Addressed code review feedback.

* Fix failing integration tests.

* Clarified handling of documents.

* Fix failing unit tests.

* Fixed further faliing integration test.
2026-05-04 10:29:00 +09:00
Andy ButlandandGitHub b499a0e121 Code Tidy: Clean up obsoleted code scheduled for removal in Umbraco 18 (IMemberGroupService) (#22632)
Remove obsolete methods on IMemberGroupService and update callers.
2026-05-03 09:47:38 +02:00
e414d05b9d Localization: Use invariant culture when parsing node paths (closes #22610) (#22625)
* Use InvariantCulture when parsing node paths.

* Add suggested validation of setup to integration test.

* Add more explicit tests for negative sign handling

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-05-03 07:40:12 +00:00
Andy ButlandandGitHub 52c133690d Media: Record the trashing user against the History audit entry (closes #22661) (#22668)
Ensure the trashing user for media is associated with the audit log entry.
2026-05-03 09:15:43 +02:00
Niels Lyngsø f61adcc1c0 improve acceptance test 2026-05-01 23:04:23 +02:00
Niels Lyngsø 64525c201f specify app loader + acceptance test queries 2026-05-01 22:13:49 +02:00
Andreas Lykke BorgandGitHub a49008b9f8 Accessibility: Added missing labels to number fields in the settings tab (#22667)
Added missing labels to fix console warning
2026-05-01 17:16:32 +02:00
Laura NetoandGitHub ef5d95a4c2 Merge branch 'release/17.4.0' into v17/hotfix/22472 2026-05-01 15:49:57 +02:00
Kenn JacobsenandGitHub f08bd93793 Cherry-picked the missing constant for "unroutable" (#22672) 2026-05-01 15:49:16 +02:00
4543856ce1 Elements: Clear element entity cache on content type changes (#22362)
fix(core): clear element entity cache on content type changes

The ContentTypeCacheRefresher clears IContent isolated cache when a
content type changes, but did not clear IElement cache. This caused
stale element entities to be returned after modifying property type
variation settings (e.g. enabling vary-by-culture), leading to 500
errors when saving elements.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-05-01 13:09:09 +00:00
Niels Lyngsø 06fb49fe7a make unit test only test output 2026-05-01 11:49:33 +02:00
Niels Lyngsø ab8e59a43f remove unused import 2026-05-01 11:44:30 +02:00
Niels Lyngsø 6037f7664c remove trash context for blocks 2026-05-01 11:36:16 +02:00
Niels Lyngsø 41ab7cbbab remove type cast 2026-05-01 11:22:06 +02:00
Niels LyngsøandCopilot 93a2d65702 JSDocs for INVARIANT umbVariantId
Co-authored-by: Copilot <copilot@github.com>
2026-05-01 11:21:37 +02:00
Niels Lyngsø 62436a4c7f resolve load promise feedback 2026-05-01 11:20:48 +02:00
Niels LyngsøandCopilot 424a5060f8 fix typescript typings
Co-authored-by: Copilot <copilot@github.com>
2026-05-01 11:19:23 +02:00
Niels Lyngsø 715831ae2a remove unused import 2026-05-01 11:09:03 +02:00
Niels Lyngsø afa0fab3fb back out if not available 2026-05-01 11:09:02 +02:00
Andreas Zerbst 1845a610a3 Makes helpers more robust by adding a hover step 2026-05-01 11:05:14 +02:00
Niels LyngsøandGitHub 59432bbbed Merge branch 'release/17.4.0' into v17/hotfix/22472 2026-05-01 10:06:03 +02:00
Niels LyngsøandCopilot a00d38eb04 readonly prop for grid,rte,single
Co-authored-by: Copilot <copilot@github.com>
2026-05-01 09:55:15 +02:00
Niels Lyngsø 2a4cdcf884 readonly as view prop 2026-05-01 09:53:44 +02:00
Niels LyngsøandCopilot efc862d301 read-only as view prop for block list
Co-authored-by: Copilot <copilot@github.com>
2026-05-01 09:53:23 +02:00
Andy ButlandandZeegaan 79e7b95253 Redirect Tracker: Prevent creation of redirects from unrouteable URLs (closes #22652, #22256) (#22657)
* Prevent creation of redirects when the old route is unroutable.

* Addressed code review feedback.

* Extend fix to handle case where a second, child page is "redirected" after preview was left open.

(cherry picked from commit 728789aaf6)
2026-05-01 16:31:30 +09:00
Zeegaan d76daf5b4e bump version 2026-05-01 16:30:27 +09:00
Niels LyngsøandCopilot 1568589576 is-trashed context + observation
Co-authored-by: Copilot <copilot@github.com>
2026-05-01 09:23:38 +02:00
Niels LyngsøandCopilot e61e0b6f51 revert language readonly rules
Co-authored-by: Copilot <copilot@github.com>
2026-05-01 09:23:27 +02:00
1edf7e9853 Ensure published querying parity between V13 and V17 (#22622)
* Ensure published querying parity between V13 and V17

* Add unit tests for published ancestor path querying

* Fix Claude review comments

* Make Unfiltered() public on the interface

* Explicitly evaluate "unfiltered" items

* A little clean-up

* Add integration tests

* Addressed code review feedback.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-05-01 09:06:04 +02:00
Niels Lyngsø 68b19a506c assign symbol for is-trashed observer 2026-05-01 08:37:09 +02:00
Kenn JacobsenandGitHub ae2318d8e9 Cache: Do not assume "published" when unpublishing a single culture (#22662) 2026-05-01 05:55:36 +02:00
Andy ButlandandGitHub 728789aaf6 Redirect Tracker: Prevent creation of redirects from unrouteable URLs (closes #22652, #22256) (#22657)
* Prevent creation of redirects when the old route is unroutable.

* Addressed code review feedback.

* Extend fix to handle case where a second, child page is "redirected" after preview was left open.
2026-05-01 09:04:22 +09:00
5a545fa122 Open API: Use Microsoft.AspNetCore.OpenApi for Open API document generation (#21058)
* Uninstall `Swashbuckle.AspNetCore` and install `Microsoft.AspNetCore.OpenApi`

Also installed `Swashbuckle.AspNetCore.SwaggerUI` for now to use as UI only.

* Registered UI and removed or commented out Swashbuckle specific code

* Started configuring the different Open API documents

* Started moving configuration

* Simplifying configuration

* Added missing configuration for the Delivery API

* Added missing configurations for Management API

Still missing polymorphism settings for both APIs

* Adjust Umbraco Extension template with OpenApi changes

* Handle sub types in open api document generation

* Renaming mime types transformer to align with others

* Added discriminator configuration

* Reference Umbraco.Cms.DevelopmentMode.Backoffice from integration tests project to avoid models mode exception being logged in tests

* Now configuring and using the HTTP json options instead of having custom transformers for handling enums and polymorphism

* Fixes to examples

* Update OpenAPI packages

* Mark most transformers as internal

* Simplify adding backoffice security requirements to your API

* Fix missing required properties

* Re-order transformers to fix missing notification headers

* Fix most build errors after regenerating client

* Fix mime types transformer being applied to Management API

* Additional fixes

* Additional fixes to file response types

* Configure Swagger UI documents

* Clear server list

* Sort APIs in UI

* Re-introduce schema handlers and fix issue with nullable enum schema name

* Simplify examples

* Small optimization

* Simplify nullability check in RequireNonNullablePropertiesSchemaTransformer

* Remove unused property

* Small fixes suggested by Claude

* Undo unintended space changes

* Add unit tests for OpenAPI transformers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add unit tests for additional OpenAPI transformers

- RequireNonNullablePropertiesSchemaTransformer (7 tests)
- BackOfficeSecurityRequirementsTransformer (10 tests)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Rename SwaggerGen classes to OpenApi for consistency

- Rename ConfigureUmbracoDeliveryApiSwaggerGenOptions to ConfigureUmbracoDeliveryApiOpenApiOptions
- Rename ConfigureUmbracoMemberAuthenticationDeliveryApiSwaggerGenOptions to ConfigureUmbracoMemberAuthenticationDeliveryApiOpenApiOptions
- Rename ConfigureUmbracoManagementApiSwaggerGenOptions to ConfigureUmbracoManagementApiOpenApiOptions
- Rename SwaggerRouteTemplatePipelineFilter to OpenApiRouteTemplatePipelineFilter
- Update DI registrations to use new class names

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update OpenAPI contract test for Microsoft.AspNetCore.OpenApi

Update expected Delivery API OpenAPI contract to reflect changes from
the migration to Microsoft.AspNetCore.OpenApi:

- OpenAPI version 3.0.4 → 3.1.1
- Nullable types now use type array format (OpenAPI 3.1 style)
- Polymorphic types use anyOf with discriminator
- Security moved from header parameter to securitySchemes
- Removed unnecessary oneOf wrappers around single $ref

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Disable Models Builder in integration tests by default

* Rename Swagger references to OpenApi for consistency

- Rename SwaggerIsEnabled to OpenApiIsEnabled
- Rename SwaggerRouteTemplate to OpenApiRouteTemplate
- Rename SwaggerUiRoutePrefix to OpenApiUiRoutePrefix
- Rename SwaggerUiConfiguration to ConfigureOpenApiUI
- Rename swaggerPipelineFilter variable to openApiPipelineFilter
- Update code comments from "Swagger JSON" to "OpenAPI specification"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Re-generate Management API open api doc and UI client after merge

* Add reference in comment to additional PR to fix file return types schema

* Fix Open API validation errors

* OpenAPI: Replace ISchemaIdHandler/ISchemaIdSelector with static UmbracoSchemaIdGenerator

Remove the DI-based schema ID handler/selector pattern and replace with a
static UmbracoSchemaIdGenerator utility class. This allows both Umbraco code
and external consumers to call the schema ID generation logic directly, which
is useful since the Microsoft OpenAPI package's schema selectors only apply
to Umbraco's own OpenAPI documents.

- Remove ISchemaIdHandler, ISchemaIdSelector interfaces and implementations
- Add static UmbracoSchemaIdGenerator.Generate() method
- Update ConfigureUmbracoOpenApiOptionsBase to use UmbracoSchemaIdGenerator directly
- Remove constructor dependencies from API options classes
- Add unit tests for UmbracoSchemaIdGenerator and CreateSchemaReferenceId

* Rename CustomOperationIdsTransformer to UmbracoOperationIdTransformer and make public

- Rename class to better reflect its purpose as Umbraco's operation ID transformer
- Change visibility from internal to public so it can be used by external consumers
- Update XML documentation to clarify usage for custom OpenAPI configurations

* OpenAPI: Update Delivery API contract test for new document format

Update expected OpenAPI output to include explicit empty values in
examples and consistent array formatting in security requirements.

* OpenAPI: Remove obsolete DocumentInclusionSelector abstraction

The document inclusion logic is now handled directly by
ConfigureUmbracoOpenApiOptionsBase.ShouldInclude(), making
the separate IDocumentInclusionSelector abstraction unnecessary.

* OpenAPI: Reorganize Management API OpenApi folder structure

- Move transformers to OpenApi/Transformers subfolder
- Move OpenApiOptionsExtensions from Extensions to OpenApi folder
- Update namespaces accordingly:
  - Umbraco.Cms.Api.Management.OpenApi.Transformers (transformers)
  - Umbraco.Cms.Api.Management.OpenApi (extensions)

* OpenAPI: Add ExcludeFromDefaultOpenApiDocument attribute

- Add [ExcludeFromDefaultOpenApiDocument] attribute for excluding controllers from the default OpenAPI document
- Make ShouldInclude method protected virtual in ConfigureUmbracoOpenApiOptionsBase for extensibility
- Override ShouldInclude in ConfigureDefaultApiOptions to check for the exclusion attribute

* OpenAPI: Add UmbracoOpenApiOptions for configuring OpenAPI routes

Add UmbracoOpenApiOptions configuration class to allow customizing:
- Enabled: Enable/disable OpenAPI and Swagger UI (default: non-production)
- RouteTemplate: Route template for OpenAPI JSON documents
- UiRoutePrefix: Route prefix for Swagger UI

Umbraco sets defaults via Configure, users can override via PostConfigure.
Simplify OpenApiRouteTemplatePipelineFilter to use options directly.

* Pipeline filters: Add OnPreMapEndpoints and rename OnEndpoints to OnPreEndpoints

- Add OnPreMapEndpoints method to IUmbracoPipelineFilter for registering
  endpoints inside UseEndpoints without calling UseEndpoints twice
- Rename OnEndpoints to OnPreEndpoints (with backward-compatible default)
- Add PreMapEndpoints and PreEndpoints properties to UmbracoPipelineFilter
- Mark OnEndpoints and Endpoints as obsolete (removal in Umbraco 19)
- Update UmbracoApplicationBuilder to call OnPreMapEndpoints inside UseEndpoints
- Remove redundant UseEndpoints() call from BackOfficeManagementApiFilter
- Update LoadTestController to use PreMapEndpoints instead of Endpoints

Co-Authored-By: Claude <noreply@anthropic.com>

* OpenAPI: Move MapOpenApi to PreMapEndpoints hook

Move OpenAPI endpoint mapping from PostPipeline to PreMapEndpoints
to avoid calling UseEndpoints twice in the pipeline.

* OpenAPI: Rename URL paths from swagger to openapi

- Change OpenAPI UI and document URLs from /umbraco/swagger to /umbraco/openapi
- Rename OAuth client constant from Swagger to OpenApiUi (value kept as
  umbraco-swagger for backwards compatibility with existing DB registrations)
- Update display name to "Umbraco OpenAPI access"
- Add DefaultUiEnabled option to allow disabling the default UI while
  keeping OpenAPI documents available (enables use of alternative UIs)
- Update MiniProfiler ignored path

Co-Authored-By: Claude <noreply@anthropic.com>

* OpenAPI: Update Microsoft.AspNetCore.OpenApi to 10.0.2

* OpenAPI: Add AddOpenApiDocumentToUi extension method

Adds a public extension method to simplify adding OpenAPI documents to the
UI document selector. This respects the configured UmbracoOpenApiOptions
route template, so users don't need to hardcode paths.

The documentTitle parameter is optional and defaults to the documentName.

Also updates the UmbracoExtension template to use the new method and
fixes the documentation URL reference.

* OpenAPI: Make OpenApiRouteTemplatePipelineFilter internal

The class has no extension points (all methods are private static) and
customization is now done via UmbracoOpenApiOptions instead.

* OpenAPI: Rename DeliveryApiSecurityFilter to DeliveryApiSecurityTransformer

Aligns naming with other OpenAPI transformers for consistency.

* OpenAPI: Simplify Delivery API member authentication configuration

Replace ConfigureUmbracoMemberAuthenticationDeliveryApiOpenApiOptions with
a simpler AddDeliveryApiOpenApiMemberAuthentication() extension method on
IServiceCollection. This hides implementation details and provides a cleaner
API for users to enable member authentication in the Delivery API OpenAPI document.

* OpenAPI: Add reference to proposal for custom JSON options support

* Move Delivery API transformers to OpenApi/Transformers folder

Aligns the folder structure with the Management API project.

* Update OpenAPI contract tests to use new URL format

Changed from /swagger/{name}/swagger.json to /openapi/{name}.json

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Delivery/DependencyInjection/UmbracoBuilderExtensions.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Fix IAuthorizationService injection detection in BackOfficeSecurityRequirementsTransformer

- Fix bug where parameter.GetType() was used instead of parameter.ParameterType,
  causing the IAuthorizationService injection check to always return false
- Replace magic number with BaseAuthorizeAttributeCount constant
- Improve comments explaining the 403 response logic
- Add test for IAuthorizationService injection detection

* Remove unnecessary InterceptorsNamespaces from API projects

* Remove default implementations from IUmbracoPipelineFilter methods

* Update documentation for Microsoft.AspNetCore.OpenApi migration

- Update CLAUDE.md files to reflect the migration from Swashbuckle to Microsoft.AspNetCore.OpenApi for document generation
- Update URL paths from /umbraco/swagger/ to /umbraco/openapi/
- Rename swaggerPath variables to openApiPath in test files
- Update references to removed types (SchemaIdHandler, OperationIdHandler, etc.) with their new equivalents (UmbracoSchemaIdGenerator, UmbracoOperationIdTransformer)
- Remove outdated technical debt reference to deleted SwaggerDocumentationFilterBase

* Update Swashbuckle.AspNetCore.SwaggerUI to 10.1.2

Fixes browser caching behavior and document URL serialization issues.

* Refactor OpenAPI contract tests with validation

- Add OpenAPI spec validation for both Delivery and Management APIs
- Delivery API: Store expected contract in external JSON file for regression testing
- Management API: Compare generated contract against expected contract endpoint
- Organize Delivery API tests under OpenApi/ subdirectory
- Auto-generate Delivery API contract file if it doesn't exist

* Update ElementReferenceResponseModel type reference after OpenAPI regeneration

* Add discriminator values to Delivery API polymorphic JSON serialization

ConfigureJsonPolymorphismOptions now passes derivedType.Name as the
discriminator value for each JsonDerivedType, ensuring the $type property
is present in responses and the OpenAPI schema is valid.

* Move Delivery API OpenAPI contract tests to Umbraco.Api.Delivery folder

* Update Microsoft.AspNetCore.OpenApi to 10.0.3 and Swashbuckle.AspNetCore.SwaggerUI to 10.1.4

* Use JsonDerivedType attributes for Delivery API polymorphic serialization

Move discriminator configuration from ContentJsonTypeResolverBase to
JsonDerivedType attributes on the interfaces. This is the standard STJ
approach and keeps the resolver available for custom overrides only.

* Add OpenAPI test for custom derived type extensibility

Extract shared test infrastructure into OpenApiTestBase and add
OpenApiCustomDerivedTypeTest to verify the OpenAPI spec remains valid
when a consumer registers a custom derived type via
ContentJsonTypeResolverBase.GetDerivedTypes.

* Fix OpenAPI contract test failing on CI due to ContinuousIntegrationBuild path normalization

[CallerFilePath] embeds a compile-time source path that gets normalized to /_/... on Azure DevOps
agents when ContinuousIntegrationBuild=true. At runtime the expected contract file is not found at
that path, causing the test to attempt Directory.CreateDirectory("/_/...") which fails with
permission denied.

Fix by reading contract files from the output directory (CopyToOutputDirectory) instead of the
compile-time source path. The [CallerFilePath] approach is kept only for writing new contracts
during local development, wrapped in a try/catch so it fails gracefully on CI.

* Bump Swashbuckle.AspNetCore.SwaggerUI to 10.1.7

* Remove duplicate InternalsVisibleTo for Umbraco.Tests.UnitTests

* Extract ReplaceOpenApiSchemaService into shared Api.Common helper

Deduplicates the internal OpenApiSchemaService replacement logic
between Management API and Delivery API into a single internal
extension method in Umbraco.Cms.Api.Common. Uses assembly and type
name checks derived from a public type (OpenApiOptions) instead of
hardcoded strings for safer matching.

* Tighten visibility and improve DI extension structure

- Mark FixFileReturnTypesTransformer as internal (temporary workaround)
- Mark AddUmbracoApiOpenApiUI and AddUmbracoApi as internal
- Rename AddUmbracoApi to AddUmbracoOpenApiDocument on IUmbracoBuilder
- Move AddOpenApiDocumentToUi to OpenApiServiceCollectionExtensions
- Encapsulate ReplaceOpenApiSchemaService inside AddUmbracoOpenApiDocument
  as an optional jsonOptionsName parameter

* Regenerate OpenApi.json to fix duplicate document patch endpoint

* Move MimeTypesTransformer to shared base and respect [Consumes]

Moves the MIME type filtering from a Delivery API-only document
transformer to a shared operation transformer in Api.Common. When
[Consumes] is present, replaces content types with exactly what it
declares (fixing application/json-patch+json on the patch endpoint).
Otherwise strips non-application/json types. Regenerates OpenApi.json
and client SDK.

* Move Umbraco-specific transformers from shared base to API configs

RequireNonNullablePropertiesSchemaTransformer, FixFileReturnTypes
Transformer, and MimeTypesTransformer are now registered only in
the Management and Delivery API configs. The default API document
(used for consumer endpoints) no longer applies these opinionated
transformers.

* Clarify XML doc for UmbracoOpenApiOptions.Enabled

* Use alphabetically-first tag across all operations for stable path sorting

* Update MimeTypesTransformer tests for operation transformer interface

* Reference dotnet/aspnetcore#66340 in ReplaceOpenApiSchemaService docs

* Add unit tests to verify OpenApiSchemaServiceExtensions usage of internal types.

* Bumped Microsoft.AspNetCore.OpenApi from 10.0.4 to 10.0.6 to match Directory.Packages.props and removed unnecessary Swashbuckle reference.

* Fix indentation.

* Defensively handle a non-integer status code response key in ResponseHeaderTransformer.

* Use TryGetValue in RequireNonNullablePropertiesSchemaTransformer to avoid potential KeyNotFoundException.

* Additional tests and clarifying comments.

* Revert accidental local dev changes to Program.cs, Web.UI.csproj and StaticAssets.csproj.

* Tighten visibility of OpenAPI configuration and transformer classes to internal

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-30 19:12:44 +00:00
Andy Butland efe1f0fe59 Merge remote-tracking branch 'origin/release/17.3.5' 2026-04-30 15:16:43 +02:00
Andy Butland f4a9310ecc Merge branch 'release/17.3.5' 2026-04-30 15:15:54 +02:00
Nhu DinhandGitHub 8a50f80f28 E2E: QA Updated acceptance tests for Global elements to match the UI changes (#22511)
* Updated element creation step due to UI changes

* Updated element creation due to UI changes - cont

* Removed unused locator

* Updated locator for elementTreeItem

* Updated tests for library to match the UI changes

* Updated locator for elementVariantDropdown

* Updated tests for element permission and start nodes

* Removed @smoke tags

* Make tests run in the pipeline

* Added comment for failing tests

* Updated tests for element start nodes as the front-end does not support adding a element as start nodes

* Fix flaky tests

* Fixed comment
2026-04-30 13:08:06 +00:00
Niels Lyngsø 151d96f127 load user at the end of loading all package modules 2026-04-30 12:51:30 +02:00
Niels LyngsøandGitHub 1486121ffa V17/hotfix/revert parts of 21982 (#22656)
* do not inherit property write permissions

* revert hidding edit actions
2026-04-30 12:49:10 +02:00
Niels Lyngsø 5cd048fe67 block language access tests 2026-04-30 12:31:06 +02:00
Niels Lyngsø db5bd9ec50 destroy consumer if existing 2026-04-30 10:58:24 +02:00
Niels Lyngsø 0908586e89 update package-lock with version number 2026-04-30 10:21:29 +02:00
Niels Lyngsø c1f7a37d2a comments and todos 2026-04-30 10:17:09 +02:00
Andy Butland e6f53b9d30 Bump version to 17.3.5. 2026-04-30 10:14:57 +02:00
Niels LyngsøandCopilot a1620c9a31 make sure load only calls once
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 10:00:45 +02:00
Niels LyngsøandCopilot b08e23d5ef comment
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 09:53:25 +02:00
Niels LyngsøandCopilot e27c16e1a9 enable routes to be undefined
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 09:45:34 +02:00
Andy ButlandandGitHub 6a754894d2 Code Tidy: Clean up further obsoleted code scheduled for removal in Umbraco 18 (IEmailSender, MemberConfigurationResponseModel, MediaPermissions) (#22642)
* Removed obsolete methods and default implementations on IEmailSender.

* Removed the obsolete and unused MemberConfigurationResponseModel.

* Remove the obsolete MediaPermissions and ensure test coverage is maintained.
2026-04-30 09:56:31 +09:00
Sven GeusensandGitHub 24b25f684a Enable single blocklist migration (#22627)
* Fix incorrect frontend propertyeditor alias

* Fix early return mistake

* Enable the plan

* Add memberTypes to the lookup
2026-04-29 15:54:20 +02:00
leekelleher 99c865e0bd Fix for broken UI test 2026-04-29 14:48:24 +01:00
Niels Lyngsø 22d12449ac revert 2026-04-29 15:46:15 +02:00
Niels Lyngsø 2174b5f690 Merge remote-tracking branch 'origin/release/17.4.0' into v17/hotfix/22472 2026-04-29 15:34:03 +02:00
Niels Lyngsø 172ea1af59 remove lazy loads from dataSourceDataMapper 2026-04-29 15:32:27 +02:00
Niels Lyngsø d56c57cf2f embed umbraco-packages 2026-04-29 15:31:20 +02:00
Niels LyngsøandCopilot e65bacbdc8 app loader
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 15:23:33 +02:00
Niels Lyngsø ce0f5e77e8 base extension initializer is loaded update 2026-04-29 15:23:27 +02:00
Niels LyngsøandCopilot 69258aadea rename comment
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 14:35:28 +02:00
Niels Lyngsø 4d6b4b187b clean up imports 2026-04-29 14:32:45 +02:00
Niels Lyngsø 402e5dfa90 refactor backoffice -> app 2026-04-29 14:22:47 +02:00
Niels Lyngsø fc93fed936 remove unused imports 2026-04-29 14:14:54 +02:00
Mads Rasmussen 6306f3d4fd Merge branch 'v17/hotfix/22472' of https://github.com/umbraco/Umbraco-CMS into v17/hotfix/22472 2026-04-29 14:11:28 +02:00
Mads Rasmussen 586052bab1 Debounce extension updates and set loaded flag 2026-04-29 14:11:18 +02:00
Niels Lyngsø 87d8cab843 remove await on load for extension initializers 2026-04-29 14:11:08 +02:00
Mads Rasmussen 48973739aa Batch register extensions with validation 2026-04-29 13:58:34 +02:00
Andy Butland b68624a961 Merge branch 'main' into v18/dev 2026-04-29 13:55:19 +02:00
Mads Rasmussen 22c7e498d3 move initializer to app element 2026-04-29 13:54:46 +02:00
Andy Butland cc373296df Remove inadvertently committed research files from source control 2026-04-29 13:52:48 +02:00
leekelleher 2e84d11c53 Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Cms.Api.Management/OpenApi.json
#	src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/backend-api/types.gen.ts
2026-04-29 12:50:06 +01:00
Lee KelleherandGitHub e37a2919fc Content Rollback: Add notification message meta property (#22631)
* Extends `UmbContentRollbackModalValue` with `UmbEntityModel`

so that the Rollback modal can return the entity-type,
to display the correct notification message.

* Housekeeping

* Added localized fallback key

* Fixed typecasting issue for deprecated Document rollback

* Reverted logic, introduced `rollbackNotificationMessage` meta prop
2026-04-29 12:36:21 +01:00
Nhu DinhandGitHub b23b25163a E2E: QA Added acceptance tests for audit trail in content (#22479)
* Added constant variables for audit trail

* Added ui helper for audit trail

* Added tests for audit trails in content

* Added test for audit trail when trash content

* Added tests for audit trail when sort. move and rollback content

* Added tests for audit trail when bulk actions

* Updated tests for creating content

* Fixed comment
2026-04-29 17:37:21 +07:00
Isioma Nnodumandmole 0c021bedec bug(#22607) Add Directory.Packages.props and update restore command (#22608)
* bug(#22607) Add Directory.Packages.props and update restore command

Updated Dockerfile to include Directory.Packages.props and modified restore command to resolve docker build errors during dotnet restore step. Resolves issue #22607

* fix(template): conditionally copy Directory.Packages.props in Dockerfile

Only copy Directory.Packages.props when CPM is enabled, as per-project
package management users won't have this file in their build context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit df3cd50e7f)
2026-04-29 11:08:08 +02:00
Mole 0af0c47f69 Docker Compose template: Improve secrets handling and add script to trust development certificates (#22613)
* Generate random guid for cert pass

* Changes from review

* Move cert generation and add script to trust cert on host machine

* Generate simple hmac key

(cherry picked from commit fcf5af3d16)
2026-04-29 11:08:04 +02:00
df3cd50e7f bug(#22607) Add Directory.Packages.props and update restore command (#22608)
* bug(#22607) Add Directory.Packages.props and update restore command 

Updated Dockerfile to include Directory.Packages.props and modified restore command to resolve docker build errors during dotnet restore step. Resolves issue #22607

* fix(template): conditionally copy Directory.Packages.props in Dockerfile

Only copy Directory.Packages.props when CPM is enabled, as per-project
package management users won't have this file in their build context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 11:06:38 +02:00
Niels LyngsøandCopilot 044950e0a4 await load all bundles
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 10:32:32 +02:00
Niels Lyngsø 2572f6f0b5 leave unregistere out 2026-04-29 09:44:09 +02:00
Niels Lyngsø 89f5e49293 package name for code editor 2026-04-29 09:41:57 +02:00
Niels Lyngsø 323a731ed1 refactor package registration logic 2026-04-29 08:59:26 +02:00
Niels Lyngsø 24177dc62d add comment 2026-04-28 16:22:48 +02:00
Niels Lyngsø 7b351b199c do not react to not existing user-data or missing context 2026-04-28 16:22:38 +02:00
2f52b7b2b8 Redirect Url Management: Implement workspace (#22624)
* add redirect tracking workspace

* change weight to match v13 order

* add missing alignment and text colour

* Align closer with referency by element

* Ad repository pattern from review

* remove obsolete

* Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/redirect-management/info-app/document-redirect-management-workspace-info-app.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Adds JSDocs

* Removed unused `created` and `documentUnique` from `UmbDocumentRedirectUrlModel`

* Align `setStatus` and `delete` return shape with other data source methods

* Align workspace context observer with sibling info-app pattern

* Polish dashboard and info-app: localize hardcoded strings, tidy templates and imports

* Apply review simplifications

- Drop duplicate `unique` guards from data source (kept at repository boundary)
- Drop unnecessary `?? []` fallbacks (`items` is non-nullable in the API type)
- Localize hardcoded zero-results strings in dashboard
- Simplify redundant length check in info-app `#getTargetUrl`
- Drop unused `userIsAdmin` from `UmbDocumentRedirectStatusModel`

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-04-28 14:22:02 +00:00
Niels Lyngsø f30178ebc5 import directly 2026-04-28 16:21:41 +02:00
Niels Lyngsø cd0a8b2478 null ctrl alias for constructor initiated observations 2026-04-28 14:56:28 +02:00
Andreas Zerbst 9bdc0709cc Updated tests to make them less fragile 2026-04-28 13:05:58 +02:00
Andreas Zerbst 632b0ae099 Updated locator to use new data-mark 2026-04-28 13:05:32 +02:00
Mads RasmussenandGitHub 3991c95c45 Current User: Reload when the current user or their groups change (#22623)
* Add action event listeners to current-user context

* Add current-user.context tests

* Update current-user.context.test.ts

* Debounce current user reloads caused by events
2026-04-28 11:52:12 +01:00
d467d57198 Rich Text Editor: Mark as supports read only (#22600)
* Mark RTE as supports read only

* RTE: Address read-only review feedback

- Remove `pointer-events: none` from `:host([readonly])` so users can select and copy text in read-only mode
- Make the editor's editable state reactive to the `readonly` property via `setEditable`
- Skip rendering the statusbar in read-only mode (mirrors the toolbar) to avoid the missing border-radius regression
- Remove the now-unused `readonly` property from `umb-tiptap-toolbar` and `umb-tiptap-statusbar`

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-04-28 10:49:34 +00:00
Niels Lyngsø 4df3fc7867 layout-headline 2026-04-28 12:44:02 +02:00
6bd3edeea3 Current User: Adds Current User workspace modal (#22268)
* init current user workspace

* adding current user workspace and their apis

* add new controllers

* add default implementation

* Update src/Umbraco.Core/Services/UserService.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/ViewModels/User/UpdateCurrentUserRequestModel.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update tests/Umbraco.Tests.Integration/Umbraco.Core/Services/UserServiceCrudTests.Update.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/Models/CurrentUserUpdateModel.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* update openApi.json, remove userKey from model, remove redundant authentication check from controllers

* update localize

* allow blob: URLs in img-src CSP for avatar

* save image change later

* Remove references to "current" user from service layer.
Align validation for user profile update with update user service method.
Controller tidy-up of dependencies.

* Add missing controller from last commit.

* resolve conflicts 2

* Renamed/relocated "current-user-workspace" to "profile/edit"

Refactored the "Edit" (profile) button logic,
to handle the check whether the user has access to the Users section.

* Removed the "Section User No Permission" condition

as no longer used.

* UI tweaks + streamlining

* Profile edit: surface save errors and avoid blob URL leak

- Show danger notification when avatar upload/delete or profile update fails
- Refresh current user after avatar upload so the store holds server URLs, not a leaking local blob
- Element save() methods now return boolean; modal keeps itself open when a save fails and no longer double-submits

* Refactored to use `asPromise()`

* Current User: Adapt edit-profile modal into a workspace extension

Replaces Umb.Modal.CurrentUserEditProfile with a workspace registered
against entityType 'current-user'. The UmbSubmittableWorkspaceContextBase
subclass owns the editable user model and pending avatar state; submit()
coordinates uploadAvatar / deleteAvatar / updateProfile and throws on
failure so the workspace stays open, relying on the repository's existing
danger notifications.

The current-user "Edit" action now opens UMB_WORKSPACE_MODAL (sidebar,
small) instead of the bespoke modal. Avatar and settings children become
presentational views wired to the workspace context.

* Current User workspace: Address review findings

- Await initial load promise in submit() to prevent a race where the save
  action fires before the first requestCurrentUser() resolves.
- Guard the avatar element's async observer setup against post-disconnect
  attachment.
- Document the split between #data (editable persisted state) and
  #pendingAvatar (transient UI state) in the workspace context.
- Remove stray JSDoc whitespace in current-user.server.data-source.ts.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-04-28 11:18:13 +01:00
b49a0905d6 Repositories: Quote table and column names in raw SQL in MemberFilterRepository (closes #22615) (#22616)
* fix raw sql with ISqlSyntaxProvider name escaping

* reduce hard coded strings

* Fix Raw Sql in MemberFilterRepository

* fix formating

* remove migrations update changes

* Update src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberFilterRepository.cs

manually validated

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Minor code tidy.

* Add further integration tests.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-28 12:07:12 +02:00
Dirk SeefeldandAndy Butland 435c4abb42 Migrations: Fix raw SQL with ISqlSyntaxProvider table and column quoting (closes #22603) (#22604)
* fix raw sql with ISqlSyntaxProvider name escaping

* reduce hard coded strings

* Fix Raw Sql in MemberFilterRepository

* fix formating

* restore MemberFilterRepository

* Correct usage of field name constant.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-28 12:07:02 +02:00
57b063f3f4 Repositories: Quote table and column names in raw SQL in MemberFilterRepository (closes #22615) (#22616)
* fix raw sql with ISqlSyntaxProvider name escaping

* reduce hard coded strings

* Fix Raw Sql in MemberFilterRepository

* fix formating

* remove migrations update changes

* Update src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberFilterRepository.cs

manually validated

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Minor code tidy.

* Add further integration tests.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-28 09:33:59 +00:00
122e1a94d9 Migrations: Fix raw SQL with ISqlSyntaxProvider table and column quoting (closes #22603) (#22604)
* fix raw sql with ISqlSyntaxProvider name escaping

* reduce hard coded strings

* Fix Raw Sql in MemberFilterRepository

* fix formating

* restore MemberFilterRepository

* Correct usage of field name constant.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-28 08:55:42 +00:00
Andy Butland 94d94e9f46 Merge branch 'main' into v18/dev 2026-04-28 10:34:36 +02:00
Niels Lyngsø b4e4a6db25 apply entity-type to the workspace data-mark 2026-04-28 10:32:00 +02:00
Andy ButlandandGitHub b67ee798d5 Integration tests: Tolerate deadlocks in concurrent external login test (#22583)
* Prevent Concurrent_Save_Same_Login_Should_Not_Throw_Duplicate_Key_Exception from failing when exceptions other than what is being guarded against are triggered.

* Addressed code review feedback.
2026-04-28 09:49:22 +02:00
Andreas ZerbstandGitHub 2aa40e7629 E2E: QA: fixed outdated acceptance tests to match frontend changes (#22590)
* Updated helpers

* Updated test
2026-04-28 07:19:16 +00:00
MoleandGitHub fcf5af3d16 Docker Compose template: Improve secrets handling and add script to trust development certificates (#22613)
* Generate random guid for cert pass

* Changes from review

* Move cert generation and add script to trust cert on host machine

* Generate simple hmac key
2026-04-28 10:06:25 +09:00
03cfdb6480 Collection: Add table kind collection view (#22163)
* Add table collection view and manifests

* Use table kind in collection example

* Update entity-name-table-column-layout.element.ts

* Recompute table rows when item hrefs change

* define and render columns from manifest

* wip language implementation

* map to unique field

* rename to label

* test implementation for users table

* clean up

* add example entity actions

* add example description

* Update table-collection-view.element.ts

* Omit base 'meta' and relax table meta type

* Hardcode description column when present

* localize column names

* Update table-collection-view.element.ts

* Type manifest on collection view elements

* Use UmbLitElement instead of LitElement

* fix types

* Update entity-name-table-column-layout.element.ts

* provide entity context for each table row

* fix breaking change and introduce a deprecation warning

* Add status column to example collection view + localize column labels

* implement the UmbTableColumnLayoutElement interface

* add tests for the table collection view

* Make host element optional; add table docs/types

* Update controller-host.mixin.ts

* Update src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-table-column-view/entity-actions-table-column-view.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update controller-host.mixin.ts

* Update entity-name-table-column-layout.element.ts

* Update entity-actions-table-column-view.element.ts

* Handle undefined row element in table rendering

Allow onRowRendered to accept an undefined element and clean up row contexts when a row is unmounted. Update the callback signature in table.element.ts and handle the undefined case in table-collection-view.element.ts by destroying the host and removing the stored context for the item to avoid memory leaks when rows are removed.

* Update controller-host.mixin.ts

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-04-27 20:04:09 +02:00
Sven GeusensandGitHub 8b504a2916 Change Element migrations to a premigrations (#22617)
* Change AddElements to a premigration

* Move AddAllowedInLibraryToContentType to premigration
2026-04-27 16:30:07 +02:00
Andreas Zerbst e4c89092e2 Block Workspace: Add data-mark for acceptance test locator 2026-04-27 13:07:33 +02:00
Niels Lyngsø f292972078 offset condition 2026-04-27 12:27:47 +02:00
Niels Lyngsø cfe5ea4a5f improve switch condition 2026-04-27 12:24:25 +02:00
Niels Lyngsø de01efe718 fix test 2026-04-27 12:24:16 +02:00
Mads Rasmussen c364d0b629 Update base-extension-initializer.controller.ts 2026-04-27 11:12:32 +02:00
Mads Rasmussen 427b32fbd4 move block language access controller to block package 2026-04-27 10:11:31 +02:00
Andy ButlandandGitHub a832090c80 Migrations: Align type attribute casing in locallink migration for integer-based legacy links (closes #22597) (#22599)
* Align GUID-via-UDI and integer locallink sources in migration to consistent type attribute casing.

* Handle Pascal cased type attributes from local links.
2026-04-27 09:31:59 +02:00
Andy ButlandandGitHub d490554458 Public Access: Honour custom IMemberGroupService in backoffice dialog (closes #22580) (#22588)
Use IMemberGroupService for public access group selection and rendering.
2026-04-27 06:48:24 +02:00
Andreas Lykke BorgandGitHub 9c0c301a26 Link picker: Added swedish translations for link picker (closes #22542) (#22596)
Added swedish translations for link picker
2026-04-26 15:09:52 +02:00
cb1bebff91 Variant-Selector: improve visual alignment for segments (#22605)
* improve visual alignment for segments

* remove expand area for segments

Co-authored-by: Copilot <copilot@github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
2026-04-26 14:43:29 +02:00
Andy ButlandandGitHub e6cba5ed09 Health Check: Add check for untrusted database constraints on SQL Server (#22592)
* Add healthcheck for verification of trusted database constraints.

* Re-use the SQL and DTO between the migration and healthcheck.
2026-04-26 09:50:31 +02:00
Andy ButlandandNiels Lyngsø 3de31c4a19 Segments: Preserve segmented property values after save (closes #22166) (#22173)
* Preserve segment-specific property values after save and publish.

* Addressed feedback from code review.

* Moved fix to a projection in UmbPropertyValuePresetVariantBuilderController.

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-04-26 09:44:26 +02:00
a056da9c85 Segments: Preserve segmented property values after save (closes #22166) (#22173)
* Preserve segment-specific property values after save and publish.

* Addressed feedback from code review.

* Moved fix to a projection in UmbPropertyValuePresetVariantBuilderController.

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-04-24 21:23:59 +00:00
Niels Lyngsø 0f2ffb96a8 more variantId tests 2026-04-24 20:28:21 +02:00
Niels Lyngsø d6e5ff11d0 more guard unit tests 2026-04-24 20:22:12 +02:00
Niels Lyngsø 2415d72651 unit test for reactive fallback feature 2026-04-24 19:38:27 +02:00
Niels Lyngsø 831593c740 remove as const 2026-04-24 19:08:38 +02:00
Niels Lyngsø 83dd3e258e mark as readonly and make js-const 2026-04-24 19:08:03 +02:00
Niels Lyngsø c8b08f76ab remove style import 2026-04-24 19:07:54 +02:00
Niels Lyngsø 41a6bf3c83 add comment for clarification 2026-04-24 19:07:46 +02:00
Niels Lyngsø ca73e81b3c revert removal of || this._isReadOnly check for component rendering 2026-04-24 18:47:11 +02:00
Niels Lyngsø 03a63364ef prevent cancelled context get to cause problems 2026-04-24 17:25:11 +02:00
Niels Lyngsø d127289031 observe fallback for property + name guards 2026-04-24 17:02:32 +02:00
Niels Lyngsø 0c55587c7e no if sentence 2026-04-24 17:02:10 +02:00
Niels Lyngsø 31dfd52b72 todo comments for future 2026-04-24 16:52:02 +02:00
Niels Lyngsø ba80e12f6c observe readOnly languages 2026-04-24 16:51:19 +02:00
Niels Lyngsø a2187801ce make guard fallback reactive 2026-04-24 16:51:04 +02:00
Niels Lyngsø 7de9a853c0 read-only tag for Block Workspace 2026-04-24 16:05:21 +02:00
4596b36ab0 Member surface controllers: Add XML documentation and unit test coverage (#22584)
* Add XML header comments and unit tests for member operation surface controllers.

* Addressed code review feedback.

* Further code review feedback.

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-04-24 13:44:00 +00:00
Niels Lyngsø cccfc33977 inherit readOnly state when block workspace is invariant 2026-04-24 15:13:36 +02:00
Niels Lyngsø 9dcc2e9c15 set fallback on readOnly 2026-04-24 14:57:15 +02:00
Niels Lyngsø dee32a4171 RTE: set manager readOnly 2026-04-24 14:56:53 +02:00
56cb682c99 Add a constant for the "unroutable content" route (#22593)
* Add a constant for the "unroutable content" route

* Add one more constant for URL provider exceptions

* Update src/Umbraco.Core/Routing/UrlProviderExtensions.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/Constants-Routing.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-24 12:53:10 +00:00
Niels Lyngsø fbd6c61225 rename file in manifest 2026-04-24 13:19:24 +02:00
Niels Lyngsø c5425fe641 Revert "transform access context into local controller"
This reverts commit 1a83d9586b.
2026-04-24 13:18:09 +02:00
32ec824dab Document Types: Show message for non-applicable Element Type settings (#22396)
* Conditionally render history & structure settings

* Show "not applicable" message instead of hiding the settings

* Refactored to reuse `#renderElementDoesNotSupport()`

* Modified "Allow in Library"

to display a message instead of hiding the field.

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-04-24 11:02:25 +00:00
Kenn JacobsenandGitHub 5e4791ea2f Fix the NullableLanguageId build errors after merge (#22589) 2026-04-24 09:42:47 +00:00
Niels Lyngsø 409c098acd strict compare on config object level, to cover multiple conditions of the same alias. 2026-04-24 11:39:00 +02:00
Niels Lyngsø 570597b78e update js docs 2026-04-24 11:37:28 +02:00
Niels Lyngsø 443b50b2eb simplify match 2026-04-24 11:36:19 +02:00
Niels Lyngsø 7b613a35fc re-introduce submit create button 2026-04-24 11:35:21 +02:00
c8ed4c1d3f Handle "broken" ancestor publish path in legacy routing (#22586)
* Handle "broken" ancestor publish path in legacy routing

* Update tests/Umbraco.Tests.Integration/Umbraco.Core/Services/DocumentUrlServiceTests.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Additional tests to validate handling of broken publish ancestor chain for invariant content

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-24 10:54:41 +02:00
Niels Lyngsø 1a83d9586b transform access context into local controller 2026-04-23 20:43:58 +02:00
Andy Butland 53d46034d5 Merge branch 'main' into v18/dev 2026-04-23 17:06:22 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Jacob Overgaard
51efbac3ea Bump the npm_and_yarn group across 3 directories with 3 updates (#22578)
* Bump the npm_and_yarn group across 3 directories with 3 updates

Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client directory: [uuid](https://github.com/uuidjs/uuid).
Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client/src/packages/core directory: [uuid](https://github.com/uuidjs/uuid).
Bumps the npm_and_yarn group with 2 updates in the /src/Umbraco.Web.UI.Login directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and [handlebars](https://github.com/handlebars-lang/handlebars.js).


Updates `uuid` from 13.0.0 to 14.0.0
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v13.0.0...v14.0.0)

Updates `uuid` from 13.0.0 to 14.0.0
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v13.0.0...v14.0.0)

Updates `vite` from 7.3.1 to 7.3.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

Removes `handlebars`

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 14.0.0
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: uuid
  dependency-version: 14.0.0
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: vite
  dependency-version: 7.3.2
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: handlebars
  dependency-version: 
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>

* deps: pin @hey-api/openapi-ts to specific version for Login

* deps: use latest Vite on the v7 line to avoid breaking runtime changes

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-04-23 13:37:02 +00:00
Jacob Overgaard 91837ebd4d Merge branch 'release/17.4.0' of https://github.com/umbraco/Umbraco-CMS into release/17.4.0 2026-04-23 11:29:17 +02:00
Jacob Overgaard dbcc982251 Merge remote-tracking branch 'origin/main' into release/17.4.0 2026-04-23 11:28:08 +02:00
d911505a00 Slider: Add minimumRange configuration for range sliders (partially closes #22067) (#22078)
* Definition and validation of minimum range for slide property editor.

* Address code review feedback.

* Treat an incorrectly configured negative minimum range as zero.

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-04-23 11:27:50 +02:00
Andy Butland 86176f7461 Subscriber Server Role: Skip URL/alias persistence on subscribers with read-only databases (closes #22570) (#22572)
* Ensure that DocumentUrlService and DocumentUrlAliasService will respect read-only, subscriber databases.

* Fixed breaking change in constructor.

* Clarified comment.

* Use pattern matching in SkipDatabaseWrites() check.
2026-04-23 11:08:01 +02:00
Andy ButlandandGitHub 107cfbf9f6 Subscriber Server Role: Skip URL/alias persistence on subscribers with read-only databases (closes #22570) (#22572)
* Ensure that DocumentUrlService and DocumentUrlAliasService will respect read-only, subscriber databases.

* Fixed breaking change in constructor.

* Clarified comment.

* Use pattern matching in SkipDatabaseWrites() check.
2026-04-23 11:02:19 +02:00
Jacob Overgaard dffd60edf6 set version to 17.4.0-rc 2026-04-23 10:30:44 +02:00
Jacob Overgaard 3ab9d7c492 Merge remote-tracking branch 'origin/main' into release/17.4.0 2026-04-23 10:28:55 +02:00
Andy ButlandandGitHub 0bf2d04885 Hosting: Make IHostingEnvironment.ApplicationMainUrl nullable (#22558)
* Make ApplicationMainUrl on IHostingEnvironment nullable.
Update usage in HttpsCheck healthcheck and add unit tests to verify refactor.

* Improves XML documentation for the property.
2026-04-23 06:21:14 +00:00
Andreas ZerbstandGitHub f1eaf604e8 Nightly Pipeline: Skip E2E and Integration stages when Build fails (#22568)
Updated dependsOn so the tests dont run if build failed/cancelled
2026-04-23 12:27:48 +07:00
Andy Butland 1045ad7ae2 Document URL Aliases: De-duplicate repeated aliases to prevent upgrade failure (#22569)
* Ensure DocumentUrlAliasService safely de-duplicates repeated aliases.

* Addressed code review feedback.
2026-04-23 06:46:43 +02:00
Andy Butland 44a42352cb Bump version to 17.5.0-rc. 2026-04-23 06:43:21 +02:00
Andy ButlandandGitHub b70e2ae7bc Document URL Aliases: De-duplicate repeated aliases to prevent upgrade failure (#22569)
* Ensure DocumentUrlAliasService safely de-duplicates repeated aliases.

* Addressed code review feedback.
2026-04-22 23:40:35 +02:00
Niels Lyngsø 52c29e3105 revert logic 2026-04-22 22:36:57 +02:00
Niels LyngsøandGitHub 5117e1ee24 Merge branch 'main' into v17/hotfix/22472 2026-04-22 22:34:23 +02:00
Niels Lyngsø 21dd725bc2 clean up 2026-04-22 22:31:07 +02:00
Niels Lyngsø 2811758e3f clean up 2026-04-22 22:29:02 +02:00
Niels Lyngsø 3878bb2009 unit test for the actual problem 2026-04-22 22:27:51 +02:00
Niels Lyngsø d3526d3448 clean up 2026-04-22 22:27:29 +02:00
Niels Lyngsø e9f85e1569 fix and clean-up 2026-04-22 22:10:51 +02:00
Niels Lyngsø cffac815f1 improve life cycle for extension initializer 2026-04-22 21:38:21 +02:00
2f09fd4ca0 Frontend: Fix umb-table Firefox rendering when columns change (closes #22411) (#22414)
* fix(frontend): use keyed repeat for umb-table columns to fix Firefox rendering (#22411)

Column rendering used .map() without keys, causing Firefox's CSS
table-* layout to break when columns changed after initial render.
Switch to repeat() with column.alias keys so Lit properly inserts/removes
DOM nodes. Also removes a stray </uui-table-cell> closing tag.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(frontend): wrap umb-table in Lit `keyed` so Firefox rebuilds the table when columns change

The `repeat()` + alias key change alone did not fix the Firefox issue: Firefox's
`display: table-*` layout engine fails to relayout when cells are inserted into
existing rows, even when Lit's keyed reconciliation does the right thing.

Wrap the `<uui-table>` render in `keyed(columnKey, ...)` so that whenever the
column set changes (keyed on the joined column aliases), Lit discards the entire
subtree and builds a fresh one. Firefox then paints a brand-new table and its
buggy incremental relayout path never runs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(frontend): document UmbTableColumn.alias uniqueness constraint

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(frontend): reattach sorter on column rebuild and harden column key

Address two review comments on the keyed() rebuild:

- UmbSorterController caches its container element on first
  initialization, so when keyed() replaces <uui-table> the sorter stays
  attached to the detached node. Toggle disable()/enable() in updated()
  when the column signature changes and the table is sortable, so the
  sorter reattaches to the fresh table.
- Build the column key via JSON.stringify instead of a pipe-joined
  string, so aliases containing '|' can't collide and defeat the rebuild.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-22 17:53:46 +01:00
Andy ButlandandGitHub 1725de6a9c Decimal: Allow decimal values when step size is not configured (closes #22127) (#22128) 2026-04-22 18:11:10 +02:00
1a316255c8 Document Management: Clear per-culture published flags when copying a document (closes #22540) (#22567)
* Content: Clear per-culture published flags when copying a document (closes #22540)

When copying a published culture-variant document, the document-level
published flag was cleared on the copy, but the per-culture published
info (mapped to umbracoDocumentCultureVariation.published) was carried
over from the source. This left the database in an inconsistent state
where the document was unpublished overall but each culture row
reported published=1.

Clear PublishCultureInfos on both the root copy and its descendants
alongside the existing Published=false assignment so no culture
variations are persisted as published on the copy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Address review feedback: use ClearPublishInfos() helper + add recursive test

- Replace direct property assignment with the existing ClearPublishInfos()
  extension method for semantic clarity and consistency with UnpublishCulture.
- Rename test to match the Can_Copy_* convention used by neighbouring tests.
- Add a second test that exercises the recursive descendant path, confirming
  per-culture published flags are also cleared on descendants.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Updates integration tests to explicitly verify the fix.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-22 15:43:08 +00:00
Niels Lyngsø 8f1d4c49fc revert 2026-04-22 17:37:14 +02:00
Niels Lyngsø 2ff73f55a4 make isPermittedForObservableVariant return undefined in bad case 2026-04-22 17:36:03 +02:00
Niels Lyngsø 4679d9df77 simplify document-block-property-level-permissions 2026-04-22 17:35:14 +02:00
Andy Butland 2daf9dae80 Merge branch 'main' into v18/dev 2026-04-22 14:34:53 +02:00
Andy ButlandandGitHub 183c85e560 Permissions: Route UI permission retrieval through IContentPermissionService (closes #22351) (#22400)
* Route UI permission retrieval through IContentPermissionService.

* Addressed code review feedback.

* Update OpenApi.json and client-side types.
2026-04-22 11:09:02 +00:00
1792cfe6f2 Surface controllers: validate redirect url in public surface controllers (#22561)
* fix: prevent open redirect in public surface controllers by validating RedirectUrl with Url.IsLocalUrl

* Update src/Umbraco.Web.Website/Controllers/UmbLoginStatusController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Web.Website/Controllers/UmbProfileController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-22 10:44:54 +00:00
Niels Lyngsø 2cb015f42b Merge branch 'main' into v17/hotfix/22472 2026-04-22 12:32:21 +02:00
Niels Lyngsø 651574db44 setup read only state based on user permissions 2026-04-22 12:31:50 +02:00
Niels Lyngsø e49387cb35 no need for async 2026-04-22 12:31:26 +02:00
Niels Lyngsø 7351409b35 stop inheriting read only 2026-04-22 12:31:13 +02:00
Andy Butland 23ad35b7d7 Merge branch 'v18/dev' of https://github.com/umbraco/Umbraco-CMS into v18/dev 2026-04-22 12:09:09 +02:00
Andy Butland 99a94fbb93 Post-merge updates for elements. 2026-04-22 12:08:48 +02:00
Andy ButlandandGitHub 28fb93f792 Backoffice: Stop UI filtering invariant document URLs by display culture (closes #22556) (#22560)
* Avoid UI filtering invariant document URLs by display culture.

* Clarified comments.
2026-04-22 11:58:29 +02:00
Andy Butland 3b3a11f31b Merge branch 'main' into v18/dev 2026-04-22 11:25:20 +02:00
f981502781 Dependencies: Revert NUnit 4 upgrade to unblock integration tests (#22562)
Revert "Dependencies: Upgrade NUnit and related test dependencies to latest major versions (#22155)"

This reverts commit 7014f9a125 on v18/dev
to resolve the Part3Of4 SQL Server integration test nightly hangs that
started around 2026-04-10.

Root cause was confirmed by hang-dump analysis: a sync-over-async call
in ContentCacheRefresher.HandleMemoryCache
(.GetAwaiter().GetResult() on an async cache method) that NUnit 3's
pumping synchronization context had been quietly completing on the test
thread. NUnit 4 dropped that behaviour, so the continuation now requires
a free thread-pool thread; under CI conditions it deadlocks.

Reverting #22155 on a branch was verified to make the nightly pass.
This is a temporary rollback to unblock v18; the proper fix is to make
ContentCacheRefresher.Refresh async end-to-end, tracked separately.

Additional adjustments beyond the pure revert to keep the branch
compiling:

- CoreConfigurationHttpTests.cs: added `using Umbraco.Cms.Core.Services;`
  for IUserService (referenced by post-#22155 code unaffected by the
  revert).
- ContentVersionCleanupServiceTest.cs: merged imports so both
  AutoFixture.NUnit3 (from revert) and Microsoft.Extensions.Options
  (from unrelated later commit) stay.
- UdiTests.cs and ContentPermissionResourceTests.cs: removed unused
  `using NUnit.Framework.Legacy;` (namespace introduced in NUnit 4).
- BackOfficeAuthorizationInitializationMiddlewareTests.cs: replaced
  `[CancelAfter(5000)]` with its NUnit 3 equivalent `[Timeout(5000)]`.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 11:04:27 +02:00
9adf5307e3 Security: Prevent XXE opportunity in OEmbedProviderBase (#22550)
* test(OEmbedProviderSecurityTests): Tests for permissive DtdProcessing (CA3075)

* fix(OEmbedProviderBase): Update GetXmlResponseAsync to prevent overly-permissive DtdProcessing

https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca3075

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* refactor(OEmbed,-OEmbedTests): close string reader inputs, linting, remove check for "DTD" in exception message

* Update src/Umbraco.Core/Media/EmbedProviders/OEmbedProviderBase.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-22 08:44:26 +00:00
65b85fd5d2 Relations: Swallow exceptions when retrieving references from incompatible property values (closes #22197) (#22207)
* Correct logging and swallowing of exceptions when retrieving references with changed property types.

* Addressed code review feedback.

* Change multi URL picker to fall back to returning an empty collection if the links JSON could not be deserialised.

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-04-22 10:31:56 +02:00
Andy ButlandandGitHub 00f0d2340e Cache: Gracefully handle inconsistent published version state (closes #22293) (#22296)
* Defensively handle case where published status in databse is corrupt.

* Addressed code review feedback.

* Further code review feedback.

* Similar fix for NRE in rebuild of document URLs.
2026-04-22 09:31:00 +02:00
Andreas ZerbstandGitHub 40a505dbc3 Integration Tests: Split Windows ManagementApi shard to avoid LocalDb memory pressure (#22559)
* Split Windows ManagementApi shard to avoid LocalDb memory pressure

* Fixed filter
2026-04-22 08:54:07 +02:00
Niels Lyngsø 49f8aab7ae parse readonly state, without variant ids as origin is the property read-only state 2026-04-22 08:16:26 +02:00
Niels Lyngsø dc2b471e4c INVARIANT variant id as static 2026-04-22 08:15:46 +02:00
Andy ButlandandGitHub 518adf51b0 Cache: Add deferred content type rebuild mode with de-duplication (#22194)
* Add option for rebuild following content type update in the background.

* Add integration test for deferred rebuild.

* Addressed code review feedback.

* add retry and graceful shutdown to deferred cache rebuild.

* Prevent shared DB connection in deferred rebuild background task.

* Move deferred rebuild trigger to post-scope notification.

* Introduce similar deferred behaviour for Examine reindexing.

* Prevent background cache rebuild from blocking foreground content saves.

* Handle potential case of primary key constraint violation when deferred rebuilding content cache and a content item is saved.

* Improved variable naming.
2026-04-22 07:55:12 +02:00
Andy ButlandandGitHub ef1f760847 Migrations: Fix Label long-string data type dbType (closes #22553) (#22557)
* Add migration to fix data type storage for labels configured with a long string value type.

* Fixed class name and added additional test from code review feedback.

* Further code review feedback.

* Add further test.
2026-04-22 12:46:00 +09:00
Andy ButlandandGitHub 5b3ab2ea2a Published Content Cache: Defensive hardening against race conditions (closes #22254, #22384) (#22393)
* Defensive checks against published content being cached as unavailable.

* Addressed code review feedback.

* Make field readonly.
2026-04-22 09:40:26 +09:00
Andy ButlandandGitHub 9dc49df369 Migrations: Optimise sortable value population for date properties (#22547)
* Optimise the populate sortable column migration.

* Further optimisation from code review feedback.
2026-04-22 09:17:34 +09:00
Andy Butland 9adac463e9 Merge branch 'main' into v18/dev 2026-04-21 15:56:36 +02:00
70d1a05a4e EF Core Scoping: Allow separate database connections for custom DbContexts (closes #22131) (#22133)
* Support separate database DbContexts in AddUmbracoDbContext.

* update internal callers to use new non-obsolete AddUmbracoDbContext overload

- UmbracoEFCoreComposer now calls the new overload with explicit shareUmbracoConnection: true
- Add #pragma CS0618 suppression for v18-obsolete overloads delegating to v19-obsolete overloads

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update further internal caller to use non-obsolete method.

* Addressed code review feedback.

* Updates after merge/final local review.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 13:18:41 +00:00
Andy ButlandandGitHub 818019dc22 Migrations: Fix local link migration losing fragments and query strings (closes #22152) (#22153)
* Correct handling of querystring and anchors in rich text local links.

* Re-organised test class.

* Address code review comments.
2026-04-21 21:22:43 +09:00
Andy ButlandandGitHub 858710cfec Output Caching: Evict cached documents when a related element is published (#22496)
Evict documents from delivery API and website output cache when related element is published.
2026-04-21 14:10:55 +02:00
Niels Lyngsø f67135a30f keep rendering edit in read-only mode 2026-04-21 13:52:51 +02:00
Andy ButlandandGitHub a42cdc6656 Members: Fix SQL error when combining member type and group filters on filter endpoint (#22209)
Fix member repository filter query construction to support filter by member type and group.
2026-04-21 13:32:12 +02:00
Andy ButlandandGitHub c64f431a23 Performance: Optimize FullDataSetRepositoryCachePolicy usage across all repositories (#22264)
* Optimize ContentTypeRepository to avoid unnecessary deep-cloning on cache reads.

* Used lightweight benchmark and addressed code review comments.

* Optimize TemplateRepository to avoid unnecessary deep-cloning on cache reads.

* Optimize DomainRepository to avoid unnecessary deep-cloning on cache reads.

* Optimize remaining repositories to avoid unnecessary deep-cloning on cache reads.
2026-04-21 13:23:23 +02:00
Andy Butland 7de26aee7e Merge branch 'main' into v18/dev 2026-04-21 13:15:22 +02:00
94336588af Users: Show success dialog after creating API user (closes #21921) (#22426)
* Present dialog for further action after creating an API user.

* Addressed code review feedback.

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-04-21 11:11:47 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Jacob Overgaard
d78eb98109 Bump the npm_and_yarn group across 3 directories with 4 updates (#22537)
* Bump the npm_and_yarn group across 3 directories with 4 updates

Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client directory: [basic-ftp](https://github.com/patrickjuchli/basic-ftp).
Bumps the npm_and_yarn group with 2 updates in the /src/Umbraco.Web.UI.Login directory: [picomatch](https://github.com/micromatch/picomatch) and [handlebars](https://github.com/handlebars-lang/handlebars.js).
Bumps the npm_and_yarn group with 1 update in the /tests/Umbraco.Tests.AcceptanceTest directory: [lodash](https://github.com/lodash/lodash).


Updates `basic-ftp` from 5.2.2 to 5.3.0
- [Release notes](https://github.com/patrickjuchli/basic-ftp/releases)
- [Changelog](https://github.com/patrickjuchli/basic-ftp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/patrickjuchli/basic-ftp/compare/v5.2.2...v5.3.0)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Removes `handlebars`

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: basic-ftp
  dependency-version: 5.3.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: handlebars
  dependency-version: 
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps-dev): bumps @hey-api/openapi-ts to 0.85.2 for everything

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-04-21 11:02:25 +00:00
Andy ButlandandGitHub dc1ac9fb8d Boot Failed: Add missing BootFailed.html error page (closes #17144) (#22120)
* Added missing "boot failed" page and adjust gitignore to include in repository.

* Adjust base path to support virtual directory hosting.
2026-04-21 19:47:13 +09:00
Jacob Overgaard 8484bab495 Issue Deduplication: Fix tool name and add manual dispatch
The allowlist referenced mcp__github__create_issue_comment, which
doesn't exist in github-mcp-server v0.17.1 (the tool is
add_issue_comment). Claude's attempts to comment were denied, so
duplicates were labelled but no explanation comment was posted.

Also adds a workflow_dispatch trigger with an issue_number input and
enables show_full_output so future denials are visible in logs.
2026-04-21 11:49:05 +02:00
LLavertyandJacob Overgaard 3de27358d5 docs(security.md): Update Sanitize HTML documentation to prefer the umbraco-cms interface instead of DOMPurify 2026-04-21 11:37:27 +02:00
Niels LyngsøandGitHub d3d0e40fd3 Eslint: Rule for Manifest Aliases (#22316)
* eslint rule for Manifest Aliases

* update to handle propertyEditorSchema aliases

* make typescript check

* support localization alias

* Make consts for theme manifests

* no rules for themes

* fix not used, double media-type-root manifest, clean up.

* Improve pascal cases test
2026-04-21 11:32:35 +02:00
Andy ButlandandGitHub 25941fd749 Members: Add lightweight external-only members (closes #12741) (#22162)
* Models, service, repository and migration for external members.

* Integrate identity for external members in MemberUserStore.

* When autolinking external member, skip member type.

* Populate profile.

* Revoke member tokens for delivery API for external members.

* Audit notification handling.

* Management API updates for external members.

* Added IMemberFilterService for combined member queries from management API.

* Referenced by member controller with external members.

* Guard password reset for external members.

* Remove ExternalMemberSettings.

* Convert between content and external members.

* Fixed ambiguous constructor.

* Update OpenApi.json.

* Update client SDK.

* Backoffice ui for external members.

* Refactor member collection retrievel to use presentation factory.
Fixes in testing.

* Fixes from testing.

* Fix icon display on member picker.

* Add external member support to member picker value converter.

* Delete fix, sync data fix, Examine indexing, member collection default icon.

* Add cache refreshers for external members.

* Remove unused "fast path" for just updating login properties.

* Addresed code review feedback.

* Further integration tests.

* Fixed failing unit test.

* Update typed client.

* Addressed code review feedback.

* Early return to reduce nesting in ReferencedByMemberController.

* Introduce MemberPresentationService and MemberReferenceService to move logic out of controllers.

* Test for and fix SQLite deadlock related to cross-store uniqueness checks.

* Additional fix for the "content" member creation.

* Defer external member Examine indexing via the background task queue.

* Add update date to external member record (aligning with content members).

* Add TreatLoginAsMemberUpdate config so member re-index can be skipped on login.

* Add logging to help verify the indexing path chosen on login and register.

* Move ExternalMemberService into Core to align with MemberService.

* Fix deserialization issue with Json payloads.

* Display of external member profile data in backoffice.

* Fixed breaking change.

* Consider existing behaviour of bumping update date on login to be a bug, so no need for configuration and backward compatibility efforts.
2026-04-21 11:28:10 +02:00
a6e6585d42 Management API: Reduce user start node tree filtering code duplication (#22486)
* Reduce user start node tree filtering code duplication

Extract shared start node filtering logic from UserStartNodeTreeControllerBase
into a dedicated service hierarchy (IUserStartNodeTreeFilterService and
domain-specific implementations for documents and media).

Existing constructor signatures and protected members are preserved as
obsolete to maintain backward compatibility for external consumers.

* Disambiguate DI constructor resolution for tree controllers

Adds obsolete constructors accepting both the legacy dependencies and the new IDocument/IMediaStartNodeTreeFilterService to the eight concrete tree controllers and to MediaTreeControllerBase. These serve as a superset constructor that lets the DI container unambiguously resolve a single constructor, since the new and existing obsolete constructors have non-subset parameter sets and [ActivatorUtilitiesConstructor] is not honoured by CallSiteFactory at ServiceProvider validation time.

* Address review feedback

- Change constructors on DocumentStartNodeTreeFilterService and
  MediaStartNodeTreeFilterService from public to internal (classes are
  already internal).
- Add [EditorBrowsable(Never)] to the disambiguation constructors so
  IDEs hide them from autocomplete.
- Add inline comments explaining the empty-array fallback in the
  obsolete GetUserStartNodeIds/GetUserStartNodePaths overrides.

* Revert filter service constructors to public

DI container requires public constructors for activation, even on
internal classes. Reverts the internal change from the previous commit.

* Add unit tests for UserStartNodeTreeFilterService

Tests ShouldBypassStartNodeFiltering (root access, data type ignore,
no access), MapWithAccessFiltering (access/no-access/missing entities),
and delegation to IUserStartNodeEntitiesService for root, child and
sibling filtering including mixed access scenarios.

* Simplify obsolete-ctor path on document and media tree controllers (#22546)

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-21 11:26:52 +02:00
Andy Butland 558a6bd724 Merge branch 'main' into v18/dev 2026-04-21 11:23:10 +02:00
Niels LyngsøandGitHub 0afa6f30fe Block Editor: Create Modal Size Overwrite (#22386)
implement data-type config for block catagloue modal size
2026-04-21 11:17:36 +02:00
Laura Neto b6a048e4f6 Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs
#	src/Umbraco.Web.UI.Client/src/assets/lang/en.ts
#	tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs
2026-04-21 11:13:15 +02:00
25d382b1c0 Removed line clamp for data type picker (closes #22515) (#22526)
* Removed line clamp for data type picker

* Removed line clamp on additional labels

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-04-21 10:55:31 +02:00
e4e6e04091 User Groups: Add ability to manage users directly from the group workspace (#22215)
* add users section into user group

* fix test failed

* fix unchange issue

* add notification

* add remainging count

* update take 100

* split user list into separate element

* add localization for text

* add repository for user list in user group

* update key message

* remove remainingCount from user-input

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-21 09:45:25 +01:00
Andreas ZerbstandGitHub 63fe8cfd55 E2E: QA: Added acceptance tests for member authentication (#22466)
* Added early steps of member auth

* Cleaned up

* Cleaned up again

* Cleaned up

* Fixes based on comments

* Updated name of helper

* Reverted to old smokeTest command
2026-04-21 08:17:12 +00:00
Andy ButlandandGitHub c507f43912 Relations: Fire relation notifications for automatic relations (closes #22222) (#22345)
* Emit relation saved and deleted notification when automatic relations are added and removed during content updates.

* Addressed code review feedback.
2026-04-21 10:16:25 +02:00
4fc3a56c8f V17/media notification (#22484)
* swapping from column to row

* adds same look for when you upload image on a content node

* Remove duplicated css property

---------

Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-04-21 08:56:50 +02:00
d58d5b246b User Service: Remove IBackOfficeUserStore service location from read methods (closes #22404) (#22408)
* Avoid requirement for IBackOfficeStore registrations for non-backoffice configured setups.

* Apply same update to other read method potentially called from non backoffice setups.

* Remove comment.

* Preserve GetUserById upgrade fallback; strengthen test assertions

- Add IRuntimeState to UserService and mirror the DbException catch
  from BackOfficeUserStore.GetAsync(int) in GetUserById, so the
  upgrade-time fallback to GetForUpgrade is preserved.
- Use non-empty arguments in the delivery-only integration test so
  the repository-backed code paths are actually exercised, not just
  the early-return guards.
- Update UserServiceCrudTests to pass IRuntimeState to the new
  constructor parameter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Introduce IBackOfficeUserReader to avoid code duplication for user read methods between UserService and BackOfficeUserStore.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-21 08:56:31 +02:00
498c1ce2b8 Hybrid Cache: Element cache (#22369)
* Implement ElementCacheService with HybridCache backing and database cache support

Fully implements ElementCacheService as the elements equivalent of DocumentCacheService,
backed by Microsoft HybridCache (L1 in-memory + L2 distributed) with database cache table
persistence via cmsContentNu.

Key changes:
- ElementCacheService: full implementation with HybridCache, draft/published separation,
  converted element L0 cache, cache tagging, preview service support, and seeding infrastructure
- IDatabaseCacheRepository: added element CRUD methods (Get/Refresh/Rebuild) with SQL queries
  using ElementDto/ElementVersionDto
- IContentCacheService: extracted common base interface shared by Document, Media and Element
  cache services (8 shared methods including Seed, Rebuild, memory cache operations)
- CacheRefreshingNotificationHandler: added element notification handling, content type changes
  now route to element or document service based on IsElement, refactored to single-pass
  classification with shared RefreshCacheForContentTypeChanges method
- ElementRefreshNotification: new notification wired to ElementRepository.OnUowRefreshedEntity
- Renamed document-specific methods for clarity (GetContentSource -> GetDocumentSource,
  RefreshContent -> RefreshDocument, CreateContentNodeKit -> CreateDocumentNodeKit,
  RebuildContentDbCache -> RebuildDocumentDbCache)
- Renamed shared DTOs (CacheRebuildDocumentDto -> CacheRebuildPublishableContentDto) since
  they're used by both documents and elements
- Extracted shared RebuildPublishableDbCache method to eliminate duplication between document
  and element rebuild logic

* Add element navigation service, publish status tracking, and breadth-first seeding

Adds the infrastructure needed for element cache seeding:

- ElementNavigationService: provides tree traversal for elements, following the
  same pattern as DocumentNavigationService/MediaNavigationService
- Split PublishStatusService into an abstract base class with DocumentPublishStatusService
  and ElementPublishStatusService subclasses, each with their own interfaces
  (IDocumentPublishStatusQueryService, IElementPublishStatusQueryService, etc.)
- ElementBreadthFirstKeyProvider: seeds the element cache on startup by traversing
  the element tree breadth-first, filtering out unpublished elements
- Element publish status is initialized on startup and kept in sync via
  ElementCacheRefresher
- Old IPublishStatusQueryService/IPublishStatusManagementService interfaces kept
  as obsolete for backward compatibility
- Non-breaking constructor changes for ContentCacheRefresher, DocumentUrlService,
  ApiContentRouteBuilder via obsolete constructor overloads

* Fix element CacheNodeFactory to set IsDraft from preview parameter

CacheNodeFactory.ToContentCacheNode(IElement, bool preview) was hardcoding
IsDraft = false instead of using the preview parameter. This caused
RefreshElementAsync to never write draft cmsContentNu rows, because
DatabaseCacheRepository.RefreshElementAsync skipped the draft write when
IsDraft was false.

* Use ElementTree lock instead of ContentTree in ElementCacheService

RefreshMemoryCacheAsync was using Constants.Locks.ContentTree instead of
Constants.Locks.ElementTree for the read lock.

* Add ElementCacheServiceTests and fix PublishStatusServiceTests for abstract base

- ElementCacheServiceTests: 9 integration tests covering draft/published retrieval,
  rebuild, delete, and RefreshElementAsync behavior
- Updated PublishStatusServiceTests to use DocumentPublishStatusService instead of
  the now-abstract PublishStatusService

* Add IPublishedElementCache facade for public element cache access

Introduces the public-facing element cache interface and implementation,
following the same pattern as IPublishedContentCache/IPublishedMediaCache.

- IPublishedElementCache: async-only interface (no legacy sync methods)
- ElementCache: facade delegating to IElementCacheService
- Added Elements property to ICacheManager, IUmbracoContext, and their
  implementations

* Add ElementHybridCacheTests and ElementHybridCacheElementTypeTests

Integration tests exercising the full element cache pipeline via
IPublishedElementCache:

ElementHybridCacheTests (7 tests):
- Draft/published retrieval by key
- Unpublished element not accessible without preview
- Draft of published element accessible
- Updated draft element reflects changes
- Deleted element removed from cache
- Element name accessible

ElementHybridCacheElementTypeTests (3 tests):
- Structural type change removes property from cached element
- Non-structural type change preserves property values
- Element removed from cache when element type is deleted

* Fix element navigation to include containers and support breadth-first seeding

The element tree contains both elements and containers (folders) with different
object types. The navigation service now queries both object types to build
the full tree hierarchy.

- Added multi-objectType overloads to INavigationRepository and
  ContentNavigationRepository using LEFT JOIN to support nodes without
  content rows (containers)
- Single-objectType methods now delegate to the multi-objectType implementation
- ElementNavigationService queries both Element and ElementContainer object types
- ElementBreadthFirstKeyProvider traverses containers without seeding them,
  only counting published elements toward the seed limit
- Added ElementBreadthFirstKeyProviderTests (9 tests) including container
  traversal scenarios

* Add ElementContentTypeSeedKeyProvider for content-type-based element seeding

Seeds elements whose content types match the configured CacheSettings.ContentTypeKeys,
mirroring the existing ContentTypeSeedKeyProvider for documents. Both providers read
from the same configuration list — document type keys seed documents, element type
keys seed elements.

* Fix ContentNavigationServiceTest mocks for multi-objectType repository overload

The single-type GetContentNodesByObjectType(Guid) now delegates to the
multi-type overload. Updated test mocks to match the IEnumerable<Guid>
signature, verifying exactly one key containing Constants.ObjectTypes.Document.

* Skip Cannot_Get_Published_Again_After_Trashing test

Trashing does not clear the published cache — this is a pre-existing issue
that also affects documents. When a cached item is trashed, the HybridCache
entry remains because RefreshMemoryCacheAsync does not remove entries when
the database returns null for trashed items.

* Replace unsafe casts with StaticServiceProvider in obsolete constructors

The obsolete constructors in ApiContentRouteBuilder and DocumentUrlService
were using direct casts from IPublishStatusQueryService to
IDocumentPublishStatusQueryService, which would fail at runtime for
external consumers compiled against pre-v18 binaries. Use
StaticServiceProvider.Instance.GetRequiredService instead, consistent
with the pattern in ContentCacheRefresher.

* Remove duplicate XML doc summary in GetElementCultureDataForNodes

* Add obsolete constructors for backward compatibility

Preserve the old constructor signatures for CacheManager,
NavigationInitializationNotificationHandler, and
PublishStatusInitializationNotificationHandler so that external
consumers compiled against pre-element-cache versions don't break.
New dependencies are resolved via StaticServiceProvider.

* Pass cancellationToken to ExistsAsync in ElementCacheService.SeedAsync

* Fix DocumentUrlServiceTests to use IDocumentPublishStatusQueryService

* Trigger Build

* Address PR review feedback

- Rename HandlePublishedAsync to HandlePublishStatusAsync in
  ContentCacheRefresher for consistency with ElementCacheRefresher
- Make ElementCacheRefresher.HandlePublishStatusAsync async to align
  with ContentCacheRefresher's pattern
- Replace inline comments with #region blocks in IDatabaseCacheRepository
- Fix double enumeration in DocumentCacheService.SeedAsync and
  ElementCacheService.SeedAsync by materializing to List before logging

* Invalidate element cache entries when trashed

Apply the same fix from #22451 (documents/media) to elements:
- ElementCacheService.RefreshElementAsync: early-return for trashed
  elements, deleting from the database cache and removing from memory.
- ElementCacheService.RefreshMemoryCacheAsync: add symmetric else
  branches so memory cache entries are removed when the database cache
  has no corresponding draft or published node (self-healing).
- Re-enable Cannot_Get_Published_Again_After_Trashing integration test.

* Move element trash cache tests to ElementHybridCacheTests

Move Cannot_Get_Trashed_As_Published and
Cannot_Get_Published_Again_After_Trashing from
ElementPublishingServiceTests to ElementHybridCacheTests where they
belong — these test cache invalidation, not publishing behavior.

Add Cannot_Get_Published_Elements_After_Folder_Trashed to verify that
trashing an element folder clears its child elements from the published
cache.

* Add element hybrid cache variant tests

Add ElementHybridCacheVariantsTests covering culture variant behavior
for the element cache: variant property values per culture, invariant
property consistency across cultures, single culture updates, single
culture publishing, and draft access to both cultures.

Add isElement parameter to
CreateContentTypeWithTwoPropertiesOneVariantAndOneInvariant to support
creating variant element types without a separate builder method.

* Rename IPublishedElementCache.GetByIdAsync to GetByKeyAsync

Align with the codebase convention where Id refers to integer
identifiers and Key refers to GUID identifiers.

* Align IDocumentPublishStatusQueryService method names with element equivalent

Add IsPublished and IsPublishedInAnyCulture to
IDocumentPublishStatusQueryService to match
IElementPublishStatusQueryService naming.

Keep IsDocumentPublished and IsDocumentPublishedInAnyCulture as obsolete
default implementations delegating to the new methods, since
IPublishStatusQueryService (which exposes these names) ships on main.

Update all internal callers to use the new names.

* Keep INNER JOIN for document/media navigation queries

Only use LEFT JOIN when the query includes container types (e.g.
element containers) which don't have umbracoContent rows. Documents
and media always have content rows, so INNER JOIN preserves query
optimizer hints for those queries.

* Consolidate breadth-first seed key provider logic into base class

Make GetSeedKeys virtual on BreadthFirstKeyProvider and introduce
ShouldSeed and ShouldTraverseChildren hooks so subclasses only need
to override filtering logic instead of duplicating the entire
traversal.

- Document: overrides ShouldSeed to filter unpublished nodes
- Element: overrides ShouldSeed + ShouldTraverseChildren (always
  traverse, since containers may have published children)
- Media: uses base defaults (seed and traverse everything)

Removes the 'new' hiding pattern and the V16 TODO.

* Revert "Rename IPublishedElementCache.GetByIdAsync to GetByKeyAsync"

This reverts commit 139d66776f.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-20 15:08:10 +00:00
ed8246390c Authorization: Fix publish with descendants returning 403 with granular permissions (closes #22140) (#22148)
* Fix branch authorization from requiring recycle bin permission.

* Use named parameters.

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-04-20 13:46:19 +00:00
46c402dda9 Upgrade Screen: Detect and display correct "from" version (closes #20980) (#22387)
* fix(api): resolve correct old version on upgrade screen (closes #20980)

The upgrade screen always showed the first version of the current major
(e.g. 17.0.0) regardless of the actual database state. This was because
UpgradeSettingsFactory constructed OldVersion from just the running
app's major version number.

The fix adds UmbracoPlan.GetVersionForState() which walks the migration
transition chain and extracts version numbers from migration type
namespaces (V_{major}_{minor}_{patch} convention). RuntimeState calls
this during startup and exposes the result via a new
IRuntimeState.CurrentMigrationVersion property (with a default null
implementation to avoid breaking changes). UpgradeSettingsFactory uses
this resolved version with a fallback to the previous behaviour.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(api): return 9.4.0 for InitialState in GetVersionForState

InitialState is the final migration state of 9.4 (the lowest supported
upgrade). Returning null caused the fallback to show <major>.0.0 for
databases at that state. Now correctly resolves to 9.4.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore(infrastructure): add TODO (V18) to update initialVersion when InitialState changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Added TODO for 18.

* Addressed code review feedback.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 14:25:58 +02:00
Andy ButlandandGitHub 27263c56ea Migrations: Await EF Core premigrations for OpenIddict (closes #22200) (#22205)
Await EF Core premigrations for OpenIddict.
2026-04-20 20:40:52 +09:00
Andy ButlandandGitHub afd885f358 Developer Tools: Add umb-bump-version skill for automating version bumps (#22438)
* Adds a bump version skill.

* Amends from code review.

* Further updates from code review.
2026-04-20 12:53:47 +02:00
Andy ButlandandGitHub 307e5d5c1b Backoffice Identity: Add Override method to IBackOfficeSecurityAccessor for background processing (#22499)
* Allow packages and hosted services to set an ambient backoffice identity via AsyncLocal for scenarios where no HttpContext is available.

* Addressed code review feedback.
2026-04-20 12:41:38 +02:00
0248dcc020 Performance: Avoid allocating a string if _publishedContentCache has a cached version in MediaCacheService. (#22535)
* Avoid allocating a string if _publishedContentCache has a cached version & removed preview param, it was always false

* Clarified comment, used GetCacheKey method from location where string was being created.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-20 10:03:44 +00:00
Andy Butland 2128aba603 Merge branch 'main' into v18/dev 2026-04-20 11:53:16 +02:00
a9a370c357 Performance: Use GeneratedRegex instead of generating at runtime in string extensions (#22534)
* Use GeneratedRegex instead of generating at runtime

* Add unit tests to verify refactored code.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-20 11:31:43 +02:00
Andy ButlandandGitHub 92c5d3f6ed Templating: Correct the updated Navigation snippet (closes #22528) (#22530)
* Corrects the navigation snippet.

* Treat Model as required in Navigation snippet.
2026-04-20 11:17:15 +02:00
927eacf5c1 Update npm dependencies for v17.4.0-rc (#22464)
* update npm dependencies for v17.4.0 minor release

* update dependencies package

* fix lint errors

* remove Dribbble from lucide to simple icons

* revert @hey-api/openapi-ts bump

* chore: regenerate sdk.gen.ts

* chore: regenerate msw sw

* chore: regenerate icons

* build: excludes "mocks/tools" from being compiled

it is an isolated project and so can be used independent of the backoffice

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-04-20 09:06:31 +00:00
Andy ButlandandGitHub bbf5760c2d Trees: Respect 'Ignore user start nodes' on expand (closes #22487) (#22510)
* Propagate tree context's additional request args to tree item children, ensuring tree item children respect the "ignore user start nodes" data type setting for content pickers.

* Add unit tests for additional request args forwarding to tree item children manager.
2026-04-20 10:55:21 +02:00
Andy ButlandandGitHub fc87b3efda Documents: Present blueprint options from collection view Create button (closes #22529) (#22533)
* Add option to select blueprint when creating a document from a collection view.

* Addressed code review feedback.
2026-04-20 10:27:02 +02:00
Mads RasmussenandClaude Sonnet 4.6 7c7073428d qa(backoffice): add client-side tests for UmbWebhookCollectionRepository
Covers requestCollection with shape validation and pagination behaviour
(take, skip, consistent total) using the kitchen sink mock set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 20:45:55 +02:00
Mads RasmussenandClaude Sonnet 4.6 e79f05e8f5 qa(backoffice): add client-side tests for UmbWebhookDetailRepository
Covers createScaffold, requestByUnique, create, save, and delete using
the kitchen sink mock set and MSW-intercepted webhook endpoints.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 20:32:36 +02:00
Mads RasmussenandClaude Sonnet 4.6 e1567d6c20 qa(backoffice): add client-side tests for UmbWebhookItemRepository
Uses the kitchen sink mock set to test requestItems and items against
the MSW-intercepted webhook item endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 19:12:48 +02:00
Niels LyngsøandGitHub a1359abeb9 Icons: extends icon data + improved search (#22436)
* extend icons with information from theseaurus

* implement new icon search logic

* clean-up data

* sorting with a backup of the name

* refactor into a controller

* improve multi word group search

* embed lucide data

* rename tech into technology

* remove paper from dollar
2026-04-17 18:29:52 +02:00
4d27e1972d Backoffice Mocks: Fixes to Kitchen Sink mock data (#22512)
* upgrade msw, migrate all interceptors, and update backoffice integration

* Fix msw test runner integration

* wip mock sets

* align news mock data

* clean up

* add interface for mock sets

* Refactor mock DBs to use dataSet directly

* export as data

* align exports

* Update index.ts

* simplify

* remove createTemplateScaffold from data set

* remove getGroupByName from mock set

* remove getGroupWithResultsByName from mock set

* remove getIndexByName from mock set

* remove unused getSearchResultsMockData function

* Add kenn mock data set with SQLite transformation scripts

Introduces a new "kenn" mock data set generated from an Umbraco SQLite database export.

Transformation scripts (devops/sqlite-to-mock/):
- Database connection helper using sql.js
- Transform scripts for data-types, document-types, media-types, documents, media, users, templates, languages, and dictionary

Generated kenn data set includes:
- 156 data types
- 48 document types with properties, containers, and compositions
- 11 media types
- 41 documents with property values and variants
- 75 media items
- 4 users and 6 user groups
- 10 templates, 2 languages, 5 dictionary items

Usage: VITE_MOCK_SET=kenn npm run dev

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix Tab/Group container type mapping in document types

The PropertyGroupType enum in Umbraco.Core defines:
- Group = 0
- Tab = 1

The transformer had this inverted. Fixed the mapping and regenerated
document-type.data.ts with correct container types.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix user group fallbackPermissions in transformer

Read permissions from umbracoUserGroup2Permission table instead of
the empty userGroupDefaultPermissions column. Also handles mapping
legacy single-letter permission codes to new Umb.Document.* format.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove deprecated createTemplateScaffold from template transformer

This function was removed from the UmbMockDataSet interface.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Move sqlite-to-mock script to main package.json

Consolidate the SQLite transformation tooling into the main package by:
- Adding sql.js, @types/sql.js, and tsx as devDependencies
- Adding sqlite-to-mock script that runs transformations and lints output
- Removing the separate devops/sqlite-to-mock/package.json and lock file

This allows the transformation scripts to reuse the main node_modules.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* add url manager and url handlers

* Add CLI parameters to sqlite-to-mock script

The script now requires db-path and set-alias arguments:
  npm run sqlite-to-mock -- <db-path> <set-alias>

Changes:
- Add configure(), getDatabase(), getOutputDir(), closeDatabase() for lazy init
- Add CLI argument parsing with validation
- Remove direct execution calls from transform scripts
- Move eslint formatting into the script

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Generate complete mock data sets and auto-discover sets

- Add generate-supporting-files.ts to create index.ts and all
  placeholder/static files needed for a complete mock data set
- Use import.meta.glob for dynamic mock set discovery instead
  of hardcoded switch statement

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add mock handler for document type configuration

Introduces a new mock handler to serve document type configuration data, updates the mock database to provide configuration, and integrates the handler into the document type mock handlers.

* make all mock data optional

* Add custom service worker to bypass static asset requests

Introduces umbServiceWorker.js to intercept and bypass static asset requests before reaching MSW, improving startup performance in Vite development.

* fix type errors

* Update template-query.manager.ts

* change to runtime load of mock data

* Update package-lock.json

* wip mock set switcher

* Use umbMockManager.availableSetNames in mock header

* remove the test set

* clean up

* move mock files to the client project root

* rename folder

* move sqllite tool into mocks folder

* clean up

* rename folder

* update the correct tsconfig file

* Update README.md

* fix path

* mock search

* add mocks for tree siblings endpoint

* add mocks for document type and media type allowed parents

* split user permissions mock data into its own mock set

* Initialize localization registry in date test

* don't use consts. Inits too much from the modules

* Update property-editor-ui-user-picker.test.ts

* Update property-value-cloner-block-grid.cloner.test.ts

* add custom permission

* make test check for custom permission in specific mock set

* use specific mock set with specific user id

* Update document-user-permission.condition.test.ts

* Update section-user-permission.condition.test.ts

* add mock manager util to internal utils

* add import map to test runner

* Move mock-data-set.types and update imports

* Exclude internal consts in export test

* Rename mock key to userPermissions

* Register mock manifests only in development

* manual merge

* Add labels and alias/label list for mock sets

* Add visibility flag for mock sets

* delete kenn mock set

* Update mock-manager.ts

* fix(mocks): correct document type composition generation in sqlite-to-mock

The compositions were reversed - grouped by parentContentTypeId instead
of childContentTypeId. In cmsContentType2ContentType, the parent is the
composed type and the child is the type using it. Also adds inheritance
vs composition detection based on umbracoNode parentId matching.

* Update src/Umbraco.Web.UI.Client/mocks/msw-handlers/member-type/structure.handlers.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/mocks/tools/sqlite-to-mock/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/mocks/db/template-detail.manager.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix mock DB slice and add safety checks

* Adds "Kitchen Sink" mock data set

* Updates to sqlite-to-mock tool

* Default mock data set tweaks

Replaces "loremflickr.com" images with local placeholders

* "Kitchen Sink" mock data updates

* feat(mocks): add member support to sqlite-to-mock tool

Add transformers for members, member types, and member groups to replace
the empty placeholder arrays. Queries cmsMember, cmsMemberType, and
cmsMember2MemberGroup tables for auth data, property visibility, and
group relationships.

* Updated "Kitchen Sink" mock data with Members

* fix(mocks): type rawData in composition-mapped files to avoid never[] inference

When all compositions arrays are empty, TypeScript infers the element
type as never, causing a type error on the .map() callback. Adding an
explicit type annotation for rawData resolves this. Also fixed in both
generators so future runs produce correctly typed output.

* feat(mocks): implement imaging resize URLs handler

Extract the umbracoFile src from media items and build resize URLs with
width, height, mode, and format query parameters. Replaces the empty
urlInfos placeholder.

* Updated placeholder images

* fix(mocks): return actual media file URLs and add missing folders endpoint

The /media/urls handler was returning ancestor-based slug paths instead
of the umbracoFile source path, causing the image cropper modal to
render a generic file preview instead of an image preview.

Also adds the missing /item/media-type/folders handler that was causing
a crash when opening the media picker.

* fix(mocks): parse JSON values stored in varcharValue column

Short JSON values like Color Picker data are stored in varcharValue
rather than textValue in SQLite. The transformers only attempted
JSON.parse on textValue, leaving varcharValue as raw strings. Now also
parses varcharValue when it starts with { or [.

Also fixes the kitchen-sink Color Picker mock data to use parsed objects.

* fix(mocks): add missing document audit log handler

Adds a handler for GET /document/{id}/audit-log that returns the shared
audit log data from the mock data set. Prevents crash in the document
workspace info view history component.

* Mock data tweaks

* move logic from msw handlers to mock services

* remove debugger

* introduce an audit log db class

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-17 17:05:38 +02:00
Niels LyngsøandGitHub 67f0eb5e4a Fix: parse hashtag strings for confirm dialog localization (#22490)
just parse hashtag strings for confirm dialog localization
2026-04-17 15:03:04 +00:00
Niels Lyngsø 50c5d4eabb remove inheritance of readonly state 2026-04-17 16:36:46 +02:00
Engiber LozadaandGitHub 6f0007df85 Media Picker: Use UUI breadcrumbs to prevent modal overflow with deep folder paths (closes #22286) (#22375)
Use breadcrumbs for media folder path
2026-04-17 14:59:38 +02:00
Jacob OvergaardandGitHub eb217d671a Update model version in issue-deduplication workflow 2026-04-17 14:34:34 +02:00
Andy ButlandandGitHub 722ca0476a Dependencies: Pin System.Security.Cryptography.Xml to resolve vulnerability warning (#22514)
Add direct reference to transitive dependency on System.Security.Cryptography.Xml to ensure we don't depend on a vulnerable version.
2026-04-17 14:27:48 +02:00
94603b6918 adds same drag styling as when dragging item in the content sectin (#22460)
* adds same drag styling as when dragging item in the content sectin

* remove unused loader css

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-04-17 12:24:00 +00:00
Jacob OvergaardandClaude Opus 4.7 948eefb624 build: allow community-opened issues to trigger dedup workflow
Pass `github_token` and set `allowed_non_write_users: "*"` so the action
bypasses the OIDC actor check, which rejects non-maintainers with
"User does not have write access on this repository". Safe here because
`permissions:` and `--allowedTools` are tightly scoped to issue ops.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:03:07 +02:00
64e6a7cf8a Backoffice Mocks: Add Webhook Mock Services + Kitchen sink mock data (#22507)
* upgrade msw, migrate all interceptors, and update backoffice integration

* Fix msw test runner integration

* wip mock sets

* align news mock data

* clean up

* add interface for mock sets

* Refactor mock DBs to use dataSet directly

* export as data

* align exports

* Update index.ts

* simplify

* remove createTemplateScaffold from data set

* remove getGroupByName from mock set

* remove getGroupWithResultsByName from mock set

* remove getIndexByName from mock set

* remove unused getSearchResultsMockData function

* Add kenn mock data set with SQLite transformation scripts

Introduces a new "kenn" mock data set generated from an Umbraco SQLite database export.

Transformation scripts (devops/sqlite-to-mock/):
- Database connection helper using sql.js
- Transform scripts for data-types, document-types, media-types, documents, media, users, templates, languages, and dictionary

Generated kenn data set includes:
- 156 data types
- 48 document types with properties, containers, and compositions
- 11 media types
- 41 documents with property values and variants
- 75 media items
- 4 users and 6 user groups
- 10 templates, 2 languages, 5 dictionary items

Usage: VITE_MOCK_SET=kenn npm run dev

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix Tab/Group container type mapping in document types

The PropertyGroupType enum in Umbraco.Core defines:
- Group = 0
- Tab = 1

The transformer had this inverted. Fixed the mapping and regenerated
document-type.data.ts with correct container types.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix user group fallbackPermissions in transformer

Read permissions from umbracoUserGroup2Permission table instead of
the empty userGroupDefaultPermissions column. Also handles mapping
legacy single-letter permission codes to new Umb.Document.* format.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove deprecated createTemplateScaffold from template transformer

This function was removed from the UmbMockDataSet interface.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Move sqlite-to-mock script to main package.json

Consolidate the SQLite transformation tooling into the main package by:
- Adding sql.js, @types/sql.js, and tsx as devDependencies
- Adding sqlite-to-mock script that runs transformations and lints output
- Removing the separate devops/sqlite-to-mock/package.json and lock file

This allows the transformation scripts to reuse the main node_modules.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* add url manager and url handlers

* Add CLI parameters to sqlite-to-mock script

The script now requires db-path and set-alias arguments:
  npm run sqlite-to-mock -- <db-path> <set-alias>

Changes:
- Add configure(), getDatabase(), getOutputDir(), closeDatabase() for lazy init
- Add CLI argument parsing with validation
- Remove direct execution calls from transform scripts
- Move eslint formatting into the script

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Generate complete mock data sets and auto-discover sets

- Add generate-supporting-files.ts to create index.ts and all
  placeholder/static files needed for a complete mock data set
- Use import.meta.glob for dynamic mock set discovery instead
  of hardcoded switch statement

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add mock handler for document type configuration

Introduces a new mock handler to serve document type configuration data, updates the mock database to provide configuration, and integrates the handler into the document type mock handlers.

* make all mock data optional

* Add custom service worker to bypass static asset requests

Introduces umbServiceWorker.js to intercept and bypass static asset requests before reaching MSW, improving startup performance in Vite development.

* fix type errors

* Update template-query.manager.ts

* change to runtime load of mock data

* Update package-lock.json

* wip mock set switcher

* Use umbMockManager.availableSetNames in mock header

* remove the test set

* clean up

* move mock files to the client project root

* rename folder

* move sqllite tool into mocks folder

* clean up

* rename folder

* update the correct tsconfig file

* Update README.md

* fix path

* mock search

* add mocks for tree siblings endpoint

* add mocks for document type and media type allowed parents

* split user permissions mock data into its own mock set

* Initialize localization registry in date test

* don't use consts. Inits too much from the modules

* Update property-editor-ui-user-picker.test.ts

* Update property-value-cloner-block-grid.cloner.test.ts

* add custom permission

* make test check for custom permission in specific mock set

* use specific mock set with specific user id

* Update document-user-permission.condition.test.ts

* Update section-user-permission.condition.test.ts

* add mock manager util to internal utils

* add import map to test runner

* Move mock-data-set.types and update imports

* Exclude internal consts in export test

* Rename mock key to userPermissions

* Register mock manifests only in development

* manual merge

* Add labels and alias/label list for mock sets

* Add visibility flag for mock sets

* delete kenn mock set

* Update mock-manager.ts

* fix(mocks): correct document type composition generation in sqlite-to-mock

The compositions were reversed - grouped by parentContentTypeId instead
of childContentTypeId. In cmsContentType2ContentType, the parent is the
composed type and the child is the type using it. Also adds inheritance
vs composition detection based on umbracoNode parentId matching.

* Update src/Umbraco.Web.UI.Client/mocks/msw-handlers/member-type/structure.handlers.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/mocks/tools/sqlite-to-mock/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/mocks/db/template-detail.manager.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix mock DB slice and add safety checks

* webhook mock plan

* init webhook mock set + handlers

* Adds "Kitchen Sink" mock data set

* Updates to sqlite-to-mock tool

* Default mock data set tweaks

Replaces "loremflickr.com" images with local placeholders

* "Kitchen Sink" mock data updates

* Add paginated list and remove collection handler

* feat(mocks): add member support to sqlite-to-mock tool

Add transformers for members, member types, and member groups to replace
the empty placeholder arrays. Queries cmsMember, cmsMemberType, and
cmsMember2MemberGroup tables for auth data, property visibility, and
group relationships.

* Updated "Kitchen Sink" mock data with Members

* fix(mocks): type rawData in composition-mapped files to avoid never[] inference

When all compositions arrays are empty, TypeScript infers the element
type as never, causing a type error on the .map() callback. Adding an
explicit type annotation for rawData resolves this. Also fixed in both
generators so future runs produce correctly typed output.

* Add webhook delivery mock data and handlers

* Add webhook event mock data and handlers

* include webhooks in kitchen sink data set

* Add flags to webhook mock; fix item response

* Support pagination in webhook events handler

* Update src/Umbraco.Web.UI.Client/mocks/db/webhook-delivery.db.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update detail.handlers.ts

* Map webhook event aliases to event objects

* remove note about being created from SQL db

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-17 13:31:41 +02:00
a06c4aa4c0 Tiptap RTE: Fix Clear Formatting errors when HTML attribute extensions aren't enabled (closes #22502) (#22509)
* TipTap: Declare Clear Formatting toolbar button's extension dependencies

* Reworked to have a loose dependency

on the `class` and `style` attribute extensions

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-04-17 10:46:35 +00:00
Jacob Overgaard 13a20c8189 build: disables debug mode for workflow 2026-04-17 12:28:23 +02:00
Jacob Overgaard 4693546e34 build: enables full output to try and see why we run out of credits 2026-04-17 09:39:20 +02:00
Jacob Overgaard 21cfb0b27d build: enables progress tracking to see if/when the job fails 2026-04-17 09:38:43 +02:00
Jacob Overgaard f2f19ba5a7 build: upgrades the actions/checkout task from v4 to v6 (latest) on all workflows 2026-04-17 09:37:23 +02:00
Jacob Overgaard b7a05c005e build: removes "issues: write" permission as this job doesn't need that 2026-04-17 09:35:47 +02:00
Jacob Overgaard 8f72b079c5 build: adds "reopened" state to the claude PR review 2026-04-17 09:35:12 +02:00
Jacob Overgaard 626a78085f build: removes base_branch parameter that is not needed (has the same value as default) 2026-04-17 09:34:18 +02:00
Jacob Overgaard 80127d4647 build: this is firstly to test out Claude and make sure the flow works, but secondly also to try and reduce the number of active issues 2026-04-17 09:33:48 +02:00
a98a6aa390 Performance: Micro-optimisation in UdiParser (eliminate closure, fix naming & formatting of exceptions) (#22506)
* Eliminate closure, fix naming & formatting of exceptions

* Added unit tests around the changed code.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-17 05:51:36 +00:00
Andy ButlandandGitHub 30977bd0ad Background Jobs: Use ApplicationMainUrl as fallback for absolute URL provision (closes #22420) (#22435)
* Use configured or detected application URL as request URL fallback in background tasks when constructing absolute URLs.

* Addresed code review feedback.
2026-04-17 14:13:27 +09:00
HenrikandGitHub 48a9fb1c38 Code Quality: Use FrozenDictionary and Array instead of Dictionary and List in EntityContainer. (#22505)
Use FrozenDictionary & array instead of Dictionary & List. Fix naming
2026-04-17 07:00:03 +02:00
HenrikandGitHub a4594a3166 Code Quality: Reduce dictionary lookups within lock (#22504)
Reduce dictionary lookups within lock
2026-04-17 06:57:21 +02:00
3b5d95abaa Code Quality/Logging: Fix 'occured' -> 'occurred' typos in log/error/comment strings (#22508)
* Fix occured typo in UserBasedPreviewTokenGenerator.cs

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

* Fix occured typo in IndexPresentationFactory.cs

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

* Fix occured typo in app-error.element.ts

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

* Fix occured typo in UmbracoRouteValueTransformer.cs

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

* Fix occured typo in DocumentUrlFactory.cs

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

* Fix occured typo in input-dropzone.element.ts

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

* Fix occured typo in CollectibleRuntimeViewCompiler.cs

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

* Fix occured typo in ExamineIndexRebuilder.cs

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

* Fix occured typo in BaseTestDatabase.cs

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

---------

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
Co-authored-by: SAY-5 <SAY-5@users.noreply.github.com>
2026-04-17 06:55:33 +02:00
2955911420 Dependencies: Update minor and patch versions (#22498)
* Update dependencies to latest minors and patches.

* Update test sdk

---------

Co-authored-by: Zeegaan <skrivdetud@gmail.com>
2026-04-17 06:37:52 +02:00
leekelleher 3de50dc707 Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/mocks/data/sets/default/media-type.data.ts
#	src/Umbraco.Web.UI.Client/mocks/data/sets/default/member-type.data.ts
#	src/Umbraco.Web.UI.Client/mocks/db/document-type.db.ts
#	src/Umbraco.Web.UI.Client/mocks/msw-handlers/document-type/structure.handlers.ts
#	src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts
#	src/Umbraco.Web.UI.Client/src/mocks/data/utils/entity/entity-recycle-bin.ts
2026-04-17 00:53:18 +01:00
760f6454f4 Backoffice Mocks: Introduce Mock Sets (#22493)
* upgrade msw, migrate all interceptors, and update backoffice integration

* Fix msw test runner integration

* wip mock sets

* align news mock data

* clean up

* add interface for mock sets

* Refactor mock DBs to use dataSet directly

* export as data

* align exports

* Update index.ts

* simplify

* remove createTemplateScaffold from data set

* remove getGroupByName from mock set

* remove getGroupWithResultsByName from mock set

* remove getIndexByName from mock set

* remove unused getSearchResultsMockData function

* Add kenn mock data set with SQLite transformation scripts

Introduces a new "kenn" mock data set generated from an Umbraco SQLite database export.

Transformation scripts (devops/sqlite-to-mock/):
- Database connection helper using sql.js
- Transform scripts for data-types, document-types, media-types, documents, media, users, templates, languages, and dictionary

Generated kenn data set includes:
- 156 data types
- 48 document types with properties, containers, and compositions
- 11 media types
- 41 documents with property values and variants
- 75 media items
- 4 users and 6 user groups
- 10 templates, 2 languages, 5 dictionary items

Usage: VITE_MOCK_SET=kenn npm run dev

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix Tab/Group container type mapping in document types

The PropertyGroupType enum in Umbraco.Core defines:
- Group = 0
- Tab = 1

The transformer had this inverted. Fixed the mapping and regenerated
document-type.data.ts with correct container types.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix user group fallbackPermissions in transformer

Read permissions from umbracoUserGroup2Permission table instead of
the empty userGroupDefaultPermissions column. Also handles mapping
legacy single-letter permission codes to new Umb.Document.* format.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove deprecated createTemplateScaffold from template transformer

This function was removed from the UmbMockDataSet interface.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Move sqlite-to-mock script to main package.json

Consolidate the SQLite transformation tooling into the main package by:
- Adding sql.js, @types/sql.js, and tsx as devDependencies
- Adding sqlite-to-mock script that runs transformations and lints output
- Removing the separate devops/sqlite-to-mock/package.json and lock file

This allows the transformation scripts to reuse the main node_modules.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* add url manager and url handlers

* Add CLI parameters to sqlite-to-mock script

The script now requires db-path and set-alias arguments:
  npm run sqlite-to-mock -- <db-path> <set-alias>

Changes:
- Add configure(), getDatabase(), getOutputDir(), closeDatabase() for lazy init
- Add CLI argument parsing with validation
- Remove direct execution calls from transform scripts
- Move eslint formatting into the script

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Generate complete mock data sets and auto-discover sets

- Add generate-supporting-files.ts to create index.ts and all
  placeholder/static files needed for a complete mock data set
- Use import.meta.glob for dynamic mock set discovery instead
  of hardcoded switch statement

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add mock handler for document type configuration

Introduces a new mock handler to serve document type configuration data, updates the mock database to provide configuration, and integrates the handler into the document type mock handlers.

* make all mock data optional

* Add custom service worker to bypass static asset requests

Introduces umbServiceWorker.js to intercept and bypass static asset requests before reaching MSW, improving startup performance in Vite development.

* fix type errors

* Update template-query.manager.ts

* change to runtime load of mock data

* Update package-lock.json

* wip mock set switcher

* Use umbMockManager.availableSetNames in mock header

* remove the test set

* clean up

* move mock files to the client project root

* rename folder

* move sqllite tool into mocks folder

* clean up

* rename folder

* update the correct tsconfig file

* Update README.md

* fix path

* mock search

* add mocks for tree siblings endpoint

* add mocks for document type and media type allowed parents

* split user permissions mock data into its own mock set

* Initialize localization registry in date test

* don't use consts. Inits too much from the modules

* Update property-editor-ui-user-picker.test.ts

* Update property-value-cloner-block-grid.cloner.test.ts

* add custom permission

* make test check for custom permission in specific mock set

* use specific mock set with specific user id

* Update document-user-permission.condition.test.ts

* Update section-user-permission.condition.test.ts

* add mock manager util to internal utils

* add import map to test runner

* Move mock-data-set.types and update imports

* Exclude internal consts in export test

* Rename mock key to userPermissions

* Register mock manifests only in development

* manual merge

* Add labels and alias/label list for mock sets

* Add visibility flag for mock sets

* delete kenn mock set

* Update mock-manager.ts

* fix(mocks): correct document type composition generation in sqlite-to-mock

The compositions were reversed - grouped by parentContentTypeId instead
of childContentTypeId. In cmsContentType2ContentType, the parent is the
composed type and the child is the type using it. Also adds inheritance
vs composition detection based on umbracoNode parentId matching.

* Update src/Umbraco.Web.UI.Client/mocks/msw-handlers/member-type/structure.handlers.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/mocks/tools/sqlite-to-mock/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/mocks/db/template-detail.manager.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix mock DB slice and add safety checks

* Adds "Kitchen Sink" mock data set

* Updates to sqlite-to-mock tool

* Default mock data set tweaks

Replaces "loremflickr.com" images with local placeholders

* "Kitchen Sink" mock data updates

* feat(mocks): add member support to sqlite-to-mock tool

Add transformers for members, member types, and member groups to replace
the empty placeholder arrays. Queries cmsMember, cmsMemberType, and
cmsMember2MemberGroup tables for auth data, property visibility, and
group relationships.

* Updated "Kitchen Sink" mock data with Members

* fix(mocks): type rawData in composition-mapped files to avoid never[] inference

When all compositions arrays are empty, TypeScript infers the element
type as never, causing a type error on the .map() callback. Adding an
explicit type annotation for rawData resolves this. Also fixed in both
generators so future runs produce correctly typed output.

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-16 20:31:11 +02:00
Andreas Lykke BorgandGitHub 0f19dc3716 TipTap Code Editor: Fix horizontal overflow in TipTap source code modal (closes #22287) (#22474)
* Fix horizontal scroll when opening Edit source code modal

* Added word-wrap to umb-code-editor
2026-04-16 18:18:09 +00:00
fbe355fdd0 Parameterise variables in SqliteSyntaxProvider and SqlServerSyntaxProvider (#22492)
* fix(SqliteSyntaxProvider.cs): parameterises the `tableName` variable when passing into `DoesPrimaryKeyExist` method

* fix(SqlServerSyntaxProvider.cs): parameterises the `tableName` variable when passing into the `DoesPrimaryKeyExist` sql statement

* test(DoesPrimaryKeyExist-test): Add test file for DoesPrimaryKeyExist

Co-authored-by: LLaverty <liamlaverty@gmail.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-16 11:02:45 +00:00
Andy Butland ad9735f5c5 Merge branch 'release/17.3.4' 2026-04-16 12:41:38 +02:00
fe8c25576e Collection Action: Refactor to use extension-with-api-slot (#21974)
* Use API-enabled slot for collection actions.

* Refactor collection actions; add APIs & button folder.

* Fixed relative import.

* Add collection create action API and UI updates.

* Mark UmbExtensionApiInitializer as type import

* Update imports.

* Add additionalOptions to collection create

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-04-16 10:18:11 +02:00
Andy Butland da486ca841 Merge branch 'main' into v18/dev 2026-04-16 09:39:15 +02:00
Andy ButlandandGitHub d603d0c820 Output Caching: Align Delivery API extensibility with website output caching (#22456)
* Align output cache extension points for the delivery API with those for the website.

* Fix issue running output cache on website and delivery API at the same time.

* Updates from testing.

* Align website default implementation with naming used for delivery API equivalents.

* Addressed code review feedback.

* Updates from self-review.
2026-04-16 09:34:30 +02:00
Andreas ZerbstandGitHub c63e2668d6 Build: Extract nbgv version step into shared template (#22480)
extract nbgv version step into shared template
2026-04-16 07:15:29 +00:00
Andy Butland 87e12b9ee2 Migrations: Fix RetrustForeignKeyAndCheckConstraints failing when data violates a constraint (#22488)
* Fix exception handling in RetrustForeignKeyAndCheckConstraints migration step.

* Addressed code review feedback.
2026-04-16 07:20:38 +02:00
Andy Butland 6ad2a17c09 Bumped version to 17.3.4. 2026-04-16 07:20:09 +02:00
Andy ButlandandGitHub 773ce35e6a Migrations: Fix RetrustForeignKeyAndCheckConstraints failing when data violates a constraint (#22488)
* Fix exception handling in RetrustForeignKeyAndCheckConstraints migration step.

* Addressed code review feedback.
2026-04-16 07:17:22 +02:00
742f0b1e2a Document Editing: Allow removal of template from a document and indicate when the selected template is no longer allowed (closes #20929) (#22348)
* Allow removal of template on a document, and indicate when the selected template is no longer allowed.

* Addressed code review feedback.

* remove duplicate inline color style on template icon

---------

Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-04-15 23:39:17 +02:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>nielslyngsoe
f8da54b79d Add loading indicator to Create menu modals (#20857)
* Initial plan

* Add loading state to document and media create modals

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>
2026-04-15 20:31:28 +02:00
HenrikandGitHub 3b11b237cb Code Quality: Eliminate closure in AppPolicedCacheDictionary (#22482)
Eliminate closure
2026-04-15 20:05:58 +02:00
Laura NetoandGitHub 8e1c6c7a39 Document Types: Prevent disabling isElement when elements of that type exist (#22454)
* Document Types: Prevent disabling isElement when elements of that type exist

Mirrors the existing document-to-element guard: switching an element type
to a document type is now blocked when elements of that type exist. Adds
ElementToDocumentHasNoContentAsync to IElementSwitchValidator and a new
ContentTypeOperationStatus.InvalidElementFlagElementHasContent mapped to
a BadRequest in the document type controller.

* Address PR review feedback for isElement guard

Extract shared HasNoContentNodesAsync helper in ElementSwitchValidator
to deduplicate DocumentToElement and ElementToDocument checks. Make
WithAllowedInLibrary conditional on isElement in test setup.

* Add end-to-end integration tests for element switch validation

Add three tests to ContentTypeEditingServiceTests that verify
UpdateAsync returns the correct operation status when element
flag changes are blocked: document-to-element with existing
content, element-to-document with existing elements, and
element-to-document when used in block structures.

* Remove default interface implementation for ElementToDocumentHasNoContentAsync

Per review feedback: custom implementations of IElementSwitchValidator are unlikely, and a default implementation hides the fact that changes to the real implementation would need to be mirrored here. Accept the small breaking change for a clearer upgrade path.
2026-04-15 17:33:10 +02:00
Niels Lyngsø e40694ff9d Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/core/tree/data/unique-tree-store.ts
#	src/Umbraco.Web.UI.Client/src/packages/data-type/tree/data-type-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/dictionary/tree/dictionary-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/tree/document-blueprint-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/document-type.tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/tree/data/document-recycle-bin-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/tree/document-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/media/media-types/tree/media-type-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/media/media/recycle-bin/tree/media-recycle-bin-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/media/media/tree/media-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/members/member-type/tree/member-type-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/static-file/tree/static-file-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/tree/partial-view-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/templating/scripts/tree/script-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/templating/stylesheets/tree/stylesheet-tree.store.ts
#	src/Umbraco.Web.UI.Client/src/packages/templating/templates/tree/template-tree.store.ts
2026-04-15 17:07:49 +02:00
ba5ec202f6 Entity Service: Batch GetAllPaths queries to avoid SQL Server parameter limit (closes #22470) (#22471)
* Group get all paths to avoid exceeding SQL Server's max parameter count.

* Move GetAllPaths batching tests to dedicated test class

Move the explicit SQL Server parameter limit tests into their own
class (EntityServiceGetAllPathsTests) with NewSchemaPerTest so the
raw SqlException surfaces instead of being masked by scope disposal.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:55:10 +02:00
37bfe65b77 Umb-icon color setting optimization (#22433)
* use currentColor as color fallback

* clean up necessary prop

* Add test color behavior coverage for umb-icon

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>
2026-04-15 12:10:10 +02:00
Jacob OvergaardandClaude Opus 4.6 244ea6c34e CI: Skip Claude review on fork PRs
Fork PRs on the `pull_request` event don't have access to repository
secrets, so the action fails and surfaces a red check on the PR. Guard
the job with a head-repo equality check so the workflow simply doesn't
run for fork PRs. Remove once upstream fork support lands
(anthropics/claude-code-action#939) and `pull_request_target` can be
re-enabled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 11:55:29 +02:00
Jacob OvergaardandClaude Opus 4.6 294b24d20d CI: Revert claude-review trigger to pull_request
pull_request_target fails at OIDC token exchange ("401 Unauthorized -
Invalid OIDC token") against Anthropic's backend, even though the
action itself supports the event (PR #579). Fork PRs will not be
auto-reviewed until the upstream issue is resolved. Kept the
pull_request_target block commented with a pointer to the issues
for when re-enabling becomes viable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 11:44:43 +02:00
Jacob OvergaardandClaude Opus 4.6 ec8f2ccf8e CI: Add actions:read to claude-review workflow permissions
Docs require actions:read at the workflow permissions level in addition
to additional_permissions on the action, so Claude's CI-reading MCP
tools can actually function. See anthropics/claude-code-action
docs/configuration.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 11:41:51 +02:00
Jacob Welander JensenandGitHub 45da578e97 Media Collection: Display upload notifications in rows rather than in columns (closes #21502) (#22467)
swapping from column to row
2026-04-15 10:53:11 +02:00
015df79ef2 Tags Property Editor: Preserve commas in tag values (closes #22413) (#22432)
* Preserve commas when provided in tags.

* Address code review feedback.

* Split commas for CSV storage, preserve for JSON

* Use tagsInput var and lowercase CSV check

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>
2026-04-15 10:19:02 +02:00
3b1956d35b Member Authentication: Add member sign-in/sign-out notifications (closes #22461) (#22463)
* feat(core): add member sign-in/sign-out notifications

Add MemberLoginSuccessNotification, MemberLoginFailedNotification,
and MemberLogoutSuccessNotification to achieve parity with the
existing backoffice user authentication notifications.

Override HandleSignIn in MemberSignInManager to publish login
success/failure notifications, and override SignOutAsync to publish
logout notifications. This follows the same pattern used by
BackOfficeSignInManager for backoffice users.

Closes #22461

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs(core): add remarks to member auth notification classes

Add <remarks> XML documentation to MemberLoginSuccessNotification,
MemberLoginFailedNotification, and MemberLogoutSuccessNotification
describing intended usage, consistent with the backoffice user
notification equivalents.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(web): use IIpResolver for member auth notification IP addresses

Use IIpResolver.GetCurrentRequestIpAddress() for consistent IP
resolution in member auth notifications, matching the pattern used
by BackOfficeUserManager.

Introduces IIpResolver as a new constructor parameter with the
existing constructor marked obsolete (removal in Umbraco 19) using
StaticServiceProvider fallback for backwards compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fixed filing unit tests.

* Added tests for new functionality.

* Ensure MemberFailedNotification is fired on invalid credentials as well as member not found.
Add the reason for the failure to the notification.

* Add tests for other failed notification publishing states.

* Clarified comments.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-15 09:52:18 +02:00
HenrikandGitHub e5bd1954a7 Code Quality: Use more appropriate types for private fields of Umbraco.Cms.Core.Enum<T> (#22475)
Use better types for Umbraco.Cms.Core.Enum<T>, array iterates faster & FrozenDictionary gets better over time. Also fixes naming warnings
2026-04-15 06:54:29 +02:00
HenrikandGitHub a62afe418d Code Quality: Use array over dictionary in private collection of PublishedContentType (#22476)
No need to iterate a Dictionary when an array can be used
2026-04-15 06:49:57 +02:00
Jacob OvergaardandClaude Sonnet 4.6 0eb0313db1 Docs: Remove duplicate TS deprecation section from root CLAUDE.md
The client CLAUDE.md's action-to-doc table already maps deprecation
to docs/deprecation.md, and the root's callout directs agents to read
the client CLAUDE.md for backoffice work. Having the pattern in both
places is redundant.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:58:44 +02:00
Jacob OvergaardandClaude Sonnet 4.6 5f19354a53 Docs: Add callout to read client CLAUDE.md for backoffice work
Agents working from the repo root now see an explicit instruction to
read the client's CLAUDE.md before touching backoffice code. Prevents
missing project-specific conventions (like UmbDeprecation) that are
documented in the client project but not the root.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:55:22 +02:00
Jacob OvergaardandClaude Sonnet 4.6 aa2e0a338f Docs: Add action-to-doc checklist to client CLAUDE.md
Maps specific actions (deprecate, create element, add tests, etc.) to
the docs that MUST be read first. Ensures developers opening only the
client folder see the requirements in their Claude context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:54:46 +02:00
Jacob OvergaardandClaude Sonnet 4.6 81e6d8ec74 Docs: Add TypeScript deprecation pattern to root CLAUDE.md
The backoffice client requires both @deprecated JSDoc AND a runtime
UmbDeprecation warning for every deprecation. This was documented in
the client's docs/deprecation.md but not referenced in the root
CLAUDE.md, causing AI agents to miss the runtime warning requirement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:49:46 +02:00
Jacob OvergaardandClaude Sonnet 4.6 956c4dc830 DevOps: Ignore .claude session artifacts, keep only skills and settings
Broadens the .claude gitignore to ignore everything except skills/
(committed for CI workflows) and settings.json (shared config).
Previously only settings.local.json was ignored, leaving lock files,
worktrees, and scheduled_tasks artifacts untracked but visible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 15:47:31 +02:00
cbe7e8a533 Cache: Invalidate published cache entries when content or media is trashed (#22451)
* Cache: Invalidate published cache entries when content or media is trashed

Trashed content and media were remaining in the published cache because
ContentRefreshNotification/MediaRefreshNotification wrote the trashed
entities back into the cache, and ContentCacheRefresher.HandleMemoryCache
could not resolve the branch descendants after HandleNavigation had moved
them to the recycle bin.

- DocumentCacheService.RefreshContentAsync / MediaCacheService.RefreshMediaAsync:
  early-return for trashed entities, deleting from the database cache and
  removing from the local memory cache.
- DocumentCacheService.RefreshMemoryCacheAsync / MediaCacheService.RefreshMemoryCacheAsync:
  added symmetric else branches so memory cache entries are removed when the
  database cache has no corresponding draft or published node (self-healing).
- ContentCacheRefresher.HandleMemoryCache: added a bin fallback to
  TryGetDescendantsKeys so broadcasted RefreshBranch payloads can resolve
  descendants moved to the recycle bin on load-balanced servers.
- Integration tests covering trashed content and media cache invalidation.

* Cache: Add tests for restoring trashed content and media

Verifies that restored content is back in the draft cache (but not the
published cache, since restore does not republish) and that restored
media is back in the cache.

* Address PR review feedback

- Add bin fallback to MediaCacheRefresher.HandleMemoryCache for
  consistency with ContentCacheRefresher.
- Remove redundant [Test] attributes alongside [TestCase].

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-14 14:32:01 +02:00
9883fb5b42 Backoffice: Add explicit controller aliases to observe() calls in tree components (#22450)
Backoffice: Add explicit controller aliases to observe() calls in tree item and default tree elements

Without explicit aliases, observe() falls back to hashing the callback's
source string on every invocation. The api setter on tree-item-element-base
and the #observeData() method on default-tree.element are called each time
the api property changes, making the hash cost and implicit deduplication
behaviour visible in hot render paths.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-04-14 11:20:21 +00:00
Andreas ZerbstandGitHub 3250e69444 E2E: QA: add member type acceptance tests (#22379)
* Updated helpers

* Added tests

* Fixed

* Updated smoke

* Fixes

* Fix smokeTest command in package.json

* Fix typo in smokeTest script key
2026-04-14 08:56:01 +00:00
Niels LyngsøandGitHub 2c7e026721 Store: Accept tokens and update MDs for general Context Consumption (#22458)
* accept a Context Token as well as a string

* update MD files
2026-04-14 08:42:34 +00:00
Callum WhyteandGitHub 8c721dcbde dotnet Templates: Remove legacy Umbraco:CMS:Content:MacroErrors from project template development configuration (#22447)
Remove legacy Umbraco:CMS:Content:MacroErrors from project template Development config
2026-04-14 09:39:26 +02:00
Laura NetoandGitHub 4638406fc9 Tests: Fix unit test build (#22453)
Fix ElementPickerValueConverterTests build by passing IPropertyRenderingContextAccessor

The PublishedProperty constructor was updated to take an
IPropertyRenderingContextAccessor as its 4th argument, but
ElementPickerValueConverterTests was not updated, breaking the
Umbraco.Tests.UnitTests build.
2026-04-13 18:54:50 +02:00
Laura Neto 704ee94101 Merge branch 'main' into v18/dev 2026-04-13 17:40:29 +02:00
Jacob OvergaardandClaude Sonnet 4.6 fcccd7da54 CI: Use pull_request_target so Claude review runs on fork PRs
pull_request events from forks cannot access OIDC tokens, causing the
job to fail. pull_request_target runs in the base repo context and has
access to secrets/OIDC while still reading the PR diff via the API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 14:27:18 +02:00
7170b45aec Migrations: Quote names when creating index (closes #22409) (#22410)
* fix raw sql

* clean up

* Use existing syntax property.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-13 11:56:26 +00:00
8f642f24fe Migrations: Consistently handle GUID casing when using SQLite (#22406)
* Ensure MigrationBase formats Guids consistently with NPoco for SQLite

SQLite is case sensitive and doesn't have the concept of uniqueidentifier - Guids are stored as uppercase strings

Add FormatGuid method to SqlSyntaxProvider to centralize the logic

* (Optional) Include default FormatGuid implementation in ISqlSyntaxProvider to make this change non-breaking

* Use ToUpperInvariant for Guids in SQLite

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Tidy up comments, fix existing indentation and add unit tests for GUID formatting.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-13 10:20:38 +00:00
Andy Butland 11fa8a45c8 Merge branch 'release/17.3.3' 2026-04-13 12:12:01 +02:00
Nhu DinhandGitHub bc477c94a9 E2E: QA Updated acceptance tests to match the recent UI changes (#22445)
* Updated tipTapSettings to match the recent changes

* Updated ui helper for insert value/dictionary/partial view button

* Updated api helper for media delivery

* Fixed api helper for verify width and height in vector graphic media
2026-04-13 09:13:50 +00:00
fbc8b605a9 RTE: Block Clipboard label Localization (closes #22412) (#22417)
* localize rte block clipboard entry label

* RTE Block Clipboard: reuse existing localization controller

Avoids alias collision from creating a new UmbLocalizationController on
hosts that already have one. Exposes the base class controller as
protected so subclasses can reuse it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:24:04 +02:00
Jacob OvergaardandClaude Opus 4.6 c56dcfd345 Docs: Clarify PR body must include closing keyword for GitHub auto-close
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:00:32 +02:00
Niels LyngsøandGitHub 1ff33e897c General: Add decoding="async" to relevant IMG-tags (#22428)
add decoding="async" to relevant imgs
2026-04-13 09:47:20 +02:00
Jacob Overgaard cbfbeb4272 devops: bump max-turns from 25 to 50 2026-04-13 09:30:15 +02:00
6c96ad1f93 Elements: Cleanup element TODOs in infrastructure (#22443)
* Remove obsolete TODO (already fixed to the extend possible)

* Remove irrelevant TODO

* Refactor publishable entity building from DTOs

* Fix TODO for presentation factory

* Move shared view models from Document to Content

* Clarify TODO after testing refactoring feasibility

* Update src/Umbraco.Cms.Api.Management/ViewModels/Content/ScheduleRequestModel.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Factories/IElementPresentationFactory.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-13 08:09:13 +02:00
Kenn JacobsenandGitHub 8cebbd23d8 Elements: Cleanup element TODOs in core (#22399)
* Cleanup element TODOs in core (first take)

* Cleanup more element TODOs in PublishableContentServiceBase and ElementEditingService

* Implement Delivery API for ElementPickerValueConverter (removes TODOs and add a few new ones)

* Move the generic implementation of PublishedElementWrapped to its own class file

* Review comments for IPublishableContentRepository
2026-04-13 08:08:39 +02:00
4a4437b500 Rendering: Use explicit dependency instead of access-via-casting (#22442)
* Use explicit dependency instead of access-via-casting

* Update src/Umbraco.PublishedCache.HybridCache/PublishedElement.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-13 07:21:08 +02:00
Andy Butland ade77ad00d User Service: Prevent fetching all permissions when no IDs are provided (#22424) 2026-04-11 12:53:34 +02:00
Andy Butland 3275541d92 Bump version to 17.3.3. 2026-04-11 12:50:02 +02:00
Andy Butland bd83df28bc Merge branch 'main' into v18/dev 2026-04-11 11:37:15 +02:00
Andy ButlandandGitHub 0f4d0a6e67 Basic Authentication: Standalone login page for frontend-only deployments (closes #22144) (#22168)
* Add login for basic authentication without backoffice.

* Add 2FA to basic authentication flow.

* Accessibility improvements.

* Add tests for BasicAuthLoginController.

* Gate controller so only used when basic authentication is enabled.
Use 2FA view even when login page is not configured.

* Add tests for BasicAuthenticationMiddleware.

* Add support for external login providers.

* Addressed code review feedback.

* Applied suggestions from code review.

* Disable and change text on submit button when logging in.

* Add custom view support.
2026-04-11 08:55:08 +00:00
95bcd8fc14 Website Rendering: Add configurable output caching for template rendered pages (#22338)
* Configuration for website output cache settings.

* Interfaces and default implementation for extension points.

* Configure the output cache policy.

* Evict cached documents through updates to related documents, media and members.

* Feedback from code review.

* Update description of service registration in IWebsiteOutputCacheDurationProvider header comment.

Co-authored-by: Sven Geusens <sge@umbraco.dk>

* Use output cache over service provider.

* Optimise and DRY-up eviction handlers.

* Only register IWebsiteOutputCacheManager when the feature is enabled.

* Remove unnecessary check on applying output cache to Umbraco pipeline.

* Add extension point for determining if requests should be cached.

* Broken up large method in DocumentOutputCacheEvictionHandler, put enabled checks around debug logging, further unit test.

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2026-04-11 06:52:03 +00:00
2b4dc2db9a User Service: Prevent fetching all permissions when no IDs are provided (#22424)
* User Service: Prevent fetching all permissions when no IDs are provided

Ensures that the UserService does not attempt to fetch permissions when the provided ID collection is empty, avoiding potentially expensive database queries that could return permissions for all nodes.

* Move guard into the shared private method and add an integration test to verify the fix.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-10 18:20:38 +00:00
AbdulazizandGitHub 3c50dc7f7b Templates: Fixes modal text styling in when inserting sections (closes #22358) (#22376)
* fixes modal text styling in Insert and Sections in Templates

* fixed review issues and added accesability for the cards so you can use keyboard

* fixing formatting changes

* fixed unused css and fixed accessability to match the card select & deselect

* fixed redundant key and click events

* fixed accessability for button and small bug with not being able to click it
2026-04-10 14:04:41 +00:00
010ceab910 Elements: Align ElementPermissionService for performance improvements (#22405)
* Align ElementPermissionService with ContentPermissionService performance improvements

* Don't fetch entities we don't need.

* Update src/Umbraco.Core/Persistence/Repositories/IEntityRepository.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Add unit tests for ElementPermissionService

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-10 12:14:25 +00:00
Jacob OvergaardandGitHub 277bd8de62 Clipboard: Localize property labels when copying to clipboard (closes #21998) (#22412) 2026-04-10 13:27:25 +02:00
f9a70b799b Block Grid: Apply language fallback to block elements within layouts (closes #22195) (#22219)
* Apply language fallback to block element expose filtering.

* Handle code review feedback.

* Use builder instead of mocks in tests.

* Fixed failing unit tests.

* Revert previous approach and move fallback handling to the block property value creator.

* Include fallback policy in published property cache key

* Recreate block elements with resolved fallback culture.

* Use correct pattern for dispose.

* Introduce and use PropertyRenderingContext.

* Tidy up Fallback.

* Use core extensions for string comparison

* Less allocations

* Avoid fallback handling when no fallback policies are provided

---------

Co-authored-by: kjac <kja@umbraco.dk>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-04-10 13:10:29 +02:00
Niels LyngsøandGitHub e04cdc2030 Login: Update styles of login screen for better color customizations (#22389)
Update styles of login screen and enables better color customizations
2026-04-10 10:50:50 +00:00
Andy Butland 273f564571 Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-04-10 12:05:35 +02:00
Andy Butland 08c65ef61f Merge branch 'release/17.3.2' 2026-04-10 12:05:21 +02:00
Jacob OvergaardandClaude Sonnet 4.6 68ec8223bd Docs: Update CLAUDE.md with final Claude workflow architecture [skip ci]
Reflects the two-workflow split, trigger phrase stripping behavior,
allowed tools, labeling for both PRs and issues, and implementation
gotchas discovered during setup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 12:03:02 +02:00
Jacob OvergaardandClaude Sonnet 4.6 6ac48ef10f DevOps: Disable show_full_output now that interactive workflow works
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:32:49 +02:00
Jacob OvergaardandClaude Sonnet 4.6 2f2722258c DevOps: Remove redundant trigger_phrase (defaults to @claude)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:28:10 +02:00
Jacob OvergaardandClaude Sonnet 4.6 199beedaac DevOps: Pass PR/issue number explicitly to Claude prompt
Claude couldn't find the PR because checkout is on main and
gh pr view with no args returns nothing. Now the PR number is
injected directly into the prompt from the GitHub event context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:27:34 +02:00
Jacob OvergaardandClaude Sonnet 4.6 81c99c0ac8 DevOps: Explicitly prevent umb-review skill and git diff in interactive workflow
Claude discovered and invoked the umb-review skill which uses git diff
against origin/main — but checkout is on main so the diff was empty.
Prompt now explicitly says to use gh pr diff, not git diff or skills.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:24:34 +02:00
Jacob OvergaardandClaude Sonnet 4.6 f822b89e98 DevOps: Allow npm and dotnet in interactive Claude workflow
Needed for @claude fix scenarios where Claude builds/tests changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:23:17 +02:00
Jacob OvergaardandClaude Sonnet 4.6 48e9e6a814 DevOps: Pre-approve gh and git Bash commands for Claude workflows
The sandbox blocks multi-command Bash operations without approval.
Allow gh and git commands so Claude can read diffs, post comments,
and apply labels without permission errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:22:16 +02:00
Jacob OvergaardandClaude Sonnet 4.6 c900a5346b DevOps: Fix prompt to account for trigger phrase stripping
The action strips @claude from the comment before passing to Claude,
so commands arrive as just 'review', 'fix', etc. Updated prompt to
match. Also default empty messages to review (PR) or help (issue).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:18:24 +02:00
Jacob OvergaardandClaude Sonnet 4.6 6a0411fa40 DevOps: Restructure interactive prompt around user intent
Prompt now reads the user's message and acts accordingly instead of
prescribing behavior. Common patterns like review/help/fix/label
are listed as examples.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:15:24 +02:00
Jacob OvergaardandClaude Sonnet 4.6 b7d3236f92 DevOps: Fix interactive workflow prompt to act on PR context
Claude was treating @claude review as a greeting instead of acting
on the PR. Made prompt explicit about reviewing immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:13:17 +02:00
Jacob OvergaardandClaude Sonnet 4.6 acc99f420f DevOps: Enable show_full_output for debugging interactive workflow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:10:51 +02:00
Jacob OvergaardandClaude Sonnet 4.6 d64579f8e3 DevOps: Restore checkout in interactive Claude workflow
Action internally runs git fetch for trusted file restoration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:05:00 +02:00
Jacob OvergaardandClaude Sonnet 4.6 f98c2fd3d2 DevOps: Remove checkout from interactive Claude workflow
Action handles repo context via GitHub API — no local files needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:59:06 +02:00
Jacob OvergaardandClaude Sonnet 4.6 3bf5de2559 DevOps: Simplify interactive Claude workflow prompt
Remove umb-review skill reference — auto-review handles thorough reviews.
Interactive workflow gives quick feedback and general assistance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:58:39 +02:00
Jacob OvergaardandClaude Sonnet 4.6 f2ff1e850e DevOps: Remove reopened trigger and max-turns limit from auto-review
With only opened/ready_for_review triggers, volume is low enough to
let Claude run without a turn limit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:57:39 +02:00
Jacob OvergaardandClaude Sonnet 4.6 17cee849d3 DevOps: Increase auto-review max-turns to 50
25 turns was insufficient — the umb-review skill needs many turns to
read docs, references, changed files, and write the review.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:56:37 +02:00
Jacob OvergaardandClaude Sonnet 4.6 7fc5a88c95 DevOps: Remove synchronize trigger from auto PR review
Only review on open/reopen/ready — use @claude review for re-reviews.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:56:16 +02:00
Jacob OvergaardandClaude Sonnet 4.6 f165a9cf3e DevOps: Switch to ANTHROPIC_API_KEY_03
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:49:08 +02:00
Jacob OvergaardandClaude Sonnet 4.6 3e119cb57f DevOps: Split Claude into two workflows (auto review + interactive)
- claude-review.yml: Auto PR review on open/push/ready (no trigger needed)
- claude.yml: Interactive — @claude comments, issue assignment/labeling

Follows anthropics/claude-code-action official examples pattern.
Full Option B gating on the interactive workflow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:46:09 +02:00
Jacob OvergaardandClaude Sonnet 4.6 427a7b264e DevOps: Add issue labeling instructions to Claude workflow
Include affected/*, area/*, and category/* labels for issues.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:42:17 +02:00
Jacob OvergaardandClaude Sonnet 4.6 52653f780a DevOps: Gate issue_comment events to avoid wasted runners
Only spin up a runner for issue_comment events that mention @claude.
All other event types pass through to the action for internal filtering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:41:20 +02:00
Jacob OvergaardandClaude Sonnet 4.6 408a8805c1 DevOps: Set base_branch to main for Claude review workflow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:25:02 +02:00
Jacob OvergaardandClaude Sonnet 4.6 1db3f2c8cc DevOps: Set max-turns 25 for Claude review workflow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:24:36 +02:00
Jacob OvergaardandClaude Sonnet 4.6 02b75c37e7 DevOps: Add checkout step — action needs git repo on disk
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:21:19 +02:00
Jacob OvergaardandClaude Sonnet 4.6 27ffb2671c DevOps: Restore prompt with review and issue instructions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:19:12 +02:00
Jacob OvergaardandClaude Sonnet 4.6 02d9b50437 DevOps: Simplify Claude workflow to match official documentation
Strip all custom logic — let claude-code-action handle everything.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:18:40 +02:00
Jacob OvergaardandClaude Sonnet 4.6 98e2eba3fe DevOps: Add actions: read permission to Claude review workflow
Lets Claude see CI status when reviewing PRs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:14:19 +02:00
Jacob OvergaardandClaude Sonnet 4.6 a6fe4e6015 DevOps: Consolidate Claude workflows into single file
Merge auto and on-demand review workflows into claude-review.yml.
Add issue support via assignee_trigger and label_trigger.
Let claude-code-action handle permission gating and trigger matching.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:12:05 +02:00
Jacob OvergaardandClaude Sonnet 4.6 9bfa56afae DevOps: Remove redundant permission check from on-demand review
claude-code-action gates on write permission by default — the manual
getCollaboratorPermissionLevel check was redundant.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:06:26 +02:00
Jacob OvergaardandClaude Sonnet 4.6 005d65a49f DevOps: Revert trigger phrase to @claude review
Clearer attribution — identifies who is performing the review.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:04:22 +02:00
Jacob OvergaardandClaude Sonnet 4.6 ed93b184fc DevOps: Add id-token: write permission for claude-code-action OIDC
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:03:56 +02:00
Jacob OvergaardandClaude Sonnet 4.6 5cc7d53ed2 DevOps: Change on-demand trigger to @umbraco review
Avoids collision with the claude-code-action bot's own @claude trigger.
Re-enables job-level filter to skip non-matching comments early.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:01:24 +02:00
87be4cfc03 DevOps: Add Claude automated PR review action (closes #AB66809) (#22407)
* DevOps: Add Claude automated PR review action (closes #AB66809)

Adds two GitHub Actions workflows that run the umb-review Claude skill on every non-draft PR and on demand via `@claude review` comments. Reviews are advisory-only and post inline comments per finding plus one summary comment per review run.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* DevOps: Disable auto/on-demand triggers for initial testing

Remove pull_request_target trigger from auto workflow (workflow_dispatch only).
Disable on-demand job until auto workflow is validated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* enables task

* adds more categories

* DevOps: Address Copilot review feedback

- Checkout PR head ref (not base) so git diff works correctly
- Use fetch-depth: 0 for triple-dot diff merge base
- Fix SHA dedup: use full SHA and paginate comment listing
- Include 'maintain' permission in on-demand gate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Docs: Document Claude automated PR review workflows in CLAUDE.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 09:59:12 +02:00
Andreas Lykke BorgandGitHub 23f4b06cc8 Accessibility: Add label to member type filter dropdown (#22397)
Added missing label to dropdown
2026-04-10 08:00:50 +02:00
Andreas Lykke BorgandGitHub b6b9bc8bf2 Accessibility: Add label and localized placeholder to picker search field (#22402)
Added label and replaced placeholder with localized term
2026-04-10 08:00:27 +02:00
Andreas Lykke BorgandGitHub 06a1e82488 Accessibility: Add labels to member workspace toggles (#22403)
Added labels to toggles missing for accessibility
2026-04-10 08:00:24 +02:00
Andy Butland c6f1cfdd4a Fixed test helpers build. 2026-04-09 21:12:25 +02:00
Andy Butland e09cf2aaf8 Fix build of integration tests and failing unit test. 2026-04-09 19:52:12 +02:00
Laura Neto ea3b0d4d59 Use correct constant for MediaBreadthFirstSeedCount initializer
MediaBreadthFirstSeedCount was initialized with StaticDocumentBreadthFirstSeedCount
instead of StaticMediaBreadthFirstSeedCount, mismatching its [DefaultValue] attribute.
2026-04-09 16:21:50 +02:00
Andy Butland 85680bd36d Merge branch 'v18/dev' of https://github.com/umbraco/Umbraco-CMS into v18/dev 2026-04-09 16:01:22 +02:00
Andy Butland 36f3bf6b9c Merge branch 'main' into v18/dev 2026-04-09 16:00:10 +02:00
8df1c3f152 Deprecations: Client-side removal of v18 deprecated code (#21984)
* chore(tree): remove deprecated tree store infrastructure

Remove the entire tree store pattern that was deprecated in favor of
direct tree repository queries. This deletes 29 tree store files,
removes the ManifestTreeStore extension type, updates all 15+ tree
repository constructors to remove store context token parameters,
cleans up manifests/constants/index exports, and migrates all
skip/take pagination to the paging property pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(workspace): remove deprecated methods and properties

Remove deprecated methods/properties across workspace contexts, menu
structures, tree items, and collections:
- Tree item context: getManifest(), loadMore()
- Content workspace: loadSegments()
- Entity detail workspace: parentUnique/parentEntityType observables,
  getParent/setParent/getParentUnique/getParentEntityType methods,
  _scaffoldProcessData (replaced by _processIncomingData)
- Menu structure contexts: #parent state, provideContext('UmbMenuStructureWorkspaceContext')
- Document/media/blueprint/member workspaces: contentTypeHasCollection,
  getCollectionAlias(), getContentTypeId() (replaced by getContentTypeUnique())
- Collection context: setManifest(), getManifest() from interface and implementation
- Bulk delete action: deprecated _items getter/setter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(core): remove deprecated type aliases and exports

Remove deprecated type aliases scheduled for v18 removal:
- PackageManifestResponse (use UmbPackageManifestResponse)
- UmbSectionDefaultElement (use UmbDefaultSectionElement)
- ConditionsCollectionView (use UmbConditionsCollectionView)
- MediaValueType (use UmbMediaValueType)
- UrlParametersRecord (use UmbUrlParametersRecord)
- ActiveVariant (use UmbActiveVariant)
- UmbPropertyValueChangeEvent class and deprecated property-value-change
  event listeners

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(ui): remove deprecated config and UI exports

- Textarea: remove deprecated minHeight/maxHeight config reads
- Image cropper modal: remove deprecated default export
- UFM filters: remove 3 deprecated camelCase filter manifests
  (StripHtmlCamelCase, TitleCaseCamelCase, WordLimitCamelCase)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(repository): make totalAfter/totalBefore mandatory in UmbTargetPagedModel

Make totalAfter and totalBefore required properties (were optional),
fulfilling the TODO to make these mandatory in v18. All downstream
tree data sources already provide these values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: fix lint formatting

Auto-fixed formatting from lint run (line wrapping, trailing newlines).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(collection): default filter parameter in element collection repositories

The UmbCollectionRepository interface defines filter as optional.
Without a default, calling requestCollection() without arguments
would throw when accessing filter.skip/filter.take.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(backoffice): resolve ESLint errors, fix pagination metadata, and remove missed deprecations

- Remove unused UmbObjectState import (ESLint error from merge)
- Remove unused offsetPaging variable in tree-item-children.manager.ts
- Fix totalBefore/totalAfter in all tree data sources to account for skip
  offset (was always reporting totalBefore: 0 regardless of skip value)
- Remove deprecated entityType property from UmbElementValueModel
  (marked for v18 removal)
- Remove deprecated _items getter/setter from UmbTrashEntityBulkAction
  (marked for v18 removal)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(backoffice): remove entityType references from tests and source after type removal

Remove entityType property from test fixtures and media-dropzone.manager.ts
following removal of the deprecated entityType from UmbElementValueModel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-04-09 13:53:48 +00:00
532d10d102 Content picker: Fix display for list items in content picker when pre-selected items exceed maximum (closes #22129) (#22395)
fix issue when display list items in content picker

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-04-09 15:35:18 +02:00
4441d6d843 Mock Server: Add missing batch handlers for content types (#22390)
* Fixes MemberType mock handler

* Fixes DocumentType mock handler

* Fixes DataType mock handler

* Fixes MediaType mock handler

* Add readBatch and refactor batch handlers

* Remove 400 response for empty doc-type batch ids

* Use type guard in filter to remove undefined

* remove unused

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-04-09 12:28:52 +00:00
Andy Butland 4b1f7e535d Management API: Fix OAuth client registration permanently skipped after transient failure (closes #22356) (#22368)
* Prevent OAuth client registration from being permanently skipped after transient failure.

* Addressed code review feedback.
2026-04-09 14:02:28 +02:00
Andy ButlandandGitHub 8d25312a1a Management API: Fix OAuth client registration permanently skipped after transient failure (closes #22356) (#22368)
* Prevent OAuth client registration from being permanently skipped after transient failure.

* Addressed code review feedback.
2026-04-09 14:00:31 +02:00
ee44dbd677 Global Elements: Create options with allowed types and entityCreateOptionAction extensions (#22265)
* entity-action manifests shuffle

* feat(elements): show allowed element types in create action modal

Replace the generic document type picker with a custom create options
modal that fetches allowed element types from the library API and
displays them alongside a folder creation option, following the
established Media create pattern.

* feat(elements): add collection create action with allowed types and folder option

Add custom collection action element that fetches allowed element types
and discovers entityCreateOptionAction extensions (e.g. folder creation),
rendering them as a button or dropdown in the collection toolbar.

* refactor(elements): use dynamic entityCreateOptionAction extensions in create modals

Replace hardcoded folder option in the element create options modal with
UmbExtensionsApiInitializer to dynamically discover entityCreateOptionAction
extensions, enabling 3rd party extensibility.

* style(elements): clean up redundant state, magic strings, and empty styles

Use UMB_ELEMENT_ROOT_ENTITY_TYPE constant instead of magic string,
remove unused _headline state and empty css template, inline
single-use getter.

* fix(elements): address PR review feedback and export missing constants

- Extend UmbNamedEntityModel instead of duplicating name field
- Add getHref() support and error handling matching core patterns
- Add max-height on scroll container, icon fallbacks, element-specific
  localization key
- Export UMB_ELEMENT_CREATE_OPTIONS_MODAL and
  UMB_ELEMENT_TYPE_STRUCTURE_REPOSITORY_ALIAS through index chain
- Add feature parity checklist to clean-code docs

* style(elements): add noElementTypes localization entry and lint tweaks

* fix(elements): handle href navigation and error handling in create options modal

Navigate via history.pushState when href is present on create option
actions. Only close modal on successful execute, keeping it open on
failure so users can retry.

* Add temporary .skip tag to element smoke tests due to UI changes - to be fixed in another PR

---------

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
Co-authored-by: Nhu Dinh <hnd@umbraco.dk>
2026-04-09 12:40:06 +01:00
Andy ButlandandClaude Opus 4.6 79cf047103 Templating: Move production mode validation from service layer to Management API (#22383)
* Revert production mode validation for templates and partial views at the service layer, and move to management API.

* Remove unused ConfigureProductionMode helper from PartialViewServiceTests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add integration tests for UpdateTemplateController production mode behavior

Tests verify that the Management API correctly blocks template content
changes while allowing metadata-only updates in production mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Restore partial view service checks.
Add integration tests for template controllers with production mode.

* Align delete with create/update for file system changes in production mode.

* Restore partial view service tests.

* Add test for update to delete template repository.

* Refactored to use single test setup method.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:51:04 +02:00
e5de587721 Templating: Move production mode validation from service layer to Management API (#22383)
* Revert production mode validation for templates and partial views at the service layer, and move to management API.

* Remove unused ConfigureProductionMode helper from PartialViewServiceTests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add integration tests for UpdateTemplateController production mode behavior

Tests verify that the Management API correctly blocks template content
changes while allowing metadata-only updates in production mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Restore partial view service checks.
Add integration tests for template controllers with production mode.

* Align delete with create/update for file system changes in production mode.

* Restore partial view service tests.

* Add test for update to delete template repository.

* Refactored to use single test setup method.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:44:36 +02:00
MoleandGitHub 05112b559f Management API: Fix ambiguous constructor in PasswordConfigurationPresentationFactory (#22391)
* Fix ambiguous constructor

* Add clarifying comment
2026-04-09 10:09:33 +00:00
Bjarne FyrstenborgandAndy Butland 5d6e3df473 Property Editor Dialog: Set height to 100% for umb-property-editor-ui-picker-modal (#22354)
Set height to 100% for ui-picker-modal element
2026-04-09 11:09:15 +02:00
Andy Butland 0cd35398be Migrations: Fix potential OptimizeInvariantUrlRecords timeout on SQL Server (closes #22377) (#22382)
Ensure parallel execution plans are not used for the OptimizeInvariantUrlRecords migration.
2026-04-09 10:52:56 +02:00
Andy Butland a9615aa729 Bumped version to 17.3.2. 2026-04-09 10:52:15 +02:00
Andy ButlandandGitHub f3863162c8 Migrations: Fix potential OptimizeInvariantUrlRecords timeout on SQL Server (closes #22377) (#22382)
Ensure parallel execution plans are not used for the OptimizeInvariantUrlRecords migration.
2026-04-09 10:48:25 +02:00
Andreas Lykke BorgandGitHub 54b6c22e84 Accessibility: Fix missing labels on uui-select elements causing console warnings (#22385) 2026-04-09 10:08:51 +02:00
Niels Lyngsø 4edfbf44e9 delay condition, good for testing 2026-04-09 09:52:41 +02:00
0fa669db94 Code Clean-up (18): Remove obsoleted code flagged for removal (Part 3) (#22335)
* remove obsolete code from services

* remove obsolete code from IEmailSenderClient

* remove obsolete code from Notifications

* unchange MemberServiceTest

* Remove obsolete code from CopyingNotification

* remove ContentFinderByUrl and ContentFinderByUrlAndTemplate

* Remove DefaultUrlProvider, remove obsolete code from ContentPermissions, update MemberRoleStoreTests

* unchange PropertyCacheLevelTests

* unchange ConvertersTests

* Update src/Umbraco.Core/Notifications/ContentCopiedNotification.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/Notifications/ContentCopyingNotification.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/Notifications/CopiedNotification.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/Notifications/CopyingNotification.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/Notifications/ElementCopiedNotification.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/Notifications/ElementCopyingNotification.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Core/Services/ContentService.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Infrastructure/Mail/BasicSmtpEmailSenderClient.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* update tests, rename, remove file tests...

* Minor formatting tidy-up.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-09 06:57:00 +00:00
e5d44cd9c3 Code Clean-up (18): Resolve V18 TODO comments (#22357)
* todo cleanup

* adding activatorUtilitiesConstructor atribute

* fix failed test by adding ActivatorUtilitiesConstructor

* Apply suggestion from @AndyButland

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Apply suggestion from @AndyButland

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Apply suggestion from @AndyButland

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Apply suggestion from @AndyButland

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Apply suggestion from @AndyButland

Co-authored-by: Andy Butland <abutland73@gmail.com>

* update umbracoPlan and remove ConfigureSecurityStampOptions

* Removed uneeded using.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-09 06:34:42 +00:00
Niels Lyngsø abc6287008 corect existing usage of map to repeat 2026-04-09 08:05:13 +02:00
20b4529196 Languages: Exclude invariant culture from list of available cultures for language creation (closes #22380) (#22381)
* Exclude invariant culture from culture list endpoint

The Invariant Culture (CultureInfo.InvariantCulture) has an empty Name
property which is not a valid ISO code for Umbraco content. Filter it
out in IsoCodeValidator to prevent it appearing in the culture list.

Fixes #22380

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add unit tests for IsoCodeValidator.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-08 16:00:05 +00:00
a616e8dc48 Added length validation to change password modal element (#21781)
* feat(Change password modal): Integrate user configuration for minimum password length frontend validation on change-password-modal element.

* feat(change-password-modal): added user-friendly message for password length

* Update minlengthMessage property in change-password modal

* Fix password input minlength attribute syntax

* feat(change-password-modal): enhance password validation with dynamic configuration and feedback

* feat(change-password-modal): prevent form submission while loading configuration based on comment copilot

* Refactor password validation to input validators

* Extract password getter and clarify minimum length guard

* Refactor password validators into helper

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>
2026-04-08 13:35:17 +00:00
Andy ButlandandGitHub 681a510a08 Unit tests: Add test coverage for ContentPermissionService (#22373)
* Add unit tests for ContentPermissionService.

* Addressed code review feedback.

* Used constants for IDs and paths in tests.
2026-04-08 13:32:02 +00:00
88335f871d User group: Fix issue icons not show when different colour than black (closes #22352) (#22372)
Fix issue icons not show when different colour than black

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-04-08 15:17:43 +02:00
Andy ButlandandGitHub f0919792a1 Slider: Persist value updates on drag-and-drop (closes #22183) (#22276)
* Persist slider value updates on drag-drop.

* Addressed code review feedback.
2026-04-08 14:35:10 +02:00
3b7d2b9fa9 CSP: Add blob: to img-src for media upload previews (#22343)
Allow "blob:" in local CSP that is necessary for media uploads.

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-04-08 11:40:25 +00:00
b3d2cabd59 Claude: Agent MD files for manifestss (#22367)
* manifests.md

* refactor

* clean up unnesecary info

* update to architecture

* update

* Update src/Umbraco.Web.UI.Client/docs/manifests.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* update

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-08 13:18:08 +02:00
Engiber LozadaandGitHub bb95d74ba8 Content type design: Fix tab overflow with scrollable navigation (closes #20876) (#22294)
* Remove flex-shrink=0 from umb-body-layout

* Avoid collapsing tabs into the dropdown

* Add arrows left and right and bind a scroll

* Add a resizeObserver to keep track when the tabs container change

* Make the sort mode scrollable

* Move the add tab button inside the tabs list container

* Restore tab scrolling and detect hidden overflow

* Create a reusable scrollable container component

* Remove unused import

* Clean up

* Add HTMLElementTagNameMap to the scrollable container

* Always render the add tab button

* Observe slot children on slotchange

* Remove unused variable
2026-04-08 13:03:38 +02:00
1c92cacb83 Cache: Fix published content not immediately routable after PublishBranch (#22341)
* Re-order ContentCacheRefresher handlers so publish status is populated before memory cache refresh.

* Address code review feedback.

* Code tidy.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-04-08 12:42:06 +02:00
5d682f69a8 UUI: Updates to UI Library version 2.0.0-alpha.1 (#21994)
* build(deps): bumps @umbraco-ui to 2.0.0-alpha.1 with new themes

* fix: updates paths to new themes

* feat: uses new uui themes for static cshtml files

* feat: updates to use UUISelectOption and UUIFormControlWithBasicsMixin

* build: copy all themes to "themes" folder

* build(uui): updates themes path so it works relatively with fonts

* build: updates minimum node.js version to build from 22 to 24 to support UUI

* fix: corrects paths to theme css

* docs: update CLAUDE.md files to reflect UUI 2.x for CMS v18

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(storybook): adds theme switcher

* docs(storybook): updates paths

* docs(web): document UUI theme CSS pipeline across build files

Add comments linking the files involved in UUI theme CSS handling:
- manifests.ts: where theme CSS paths are declared, with note on UUI origin
- external/uui/vite.config.ts: where themes are copied for production builds
- vite.config.ts: where themes are copied for dev server and PR previews
- copy-to-cms.js: clarifies UUI themes are already in dist-cms at this point

Each file points to the others, making the dependency on UUI theme
filenames visible without adding abstraction.

https://claude.ai/code/session_015ntS4GXa4s9BQHsjvigDh2

* Update package.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: adjusts types

* update lockfile

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-04-08 10:36:23 +00:00
4396c3fe4b Integration Tests: Fix raw SQL statements in DocumentUrlTests (closes issue #22360) (#22365)
* fix raw sql statements

* use ISqlSyntaxProvider methods

* Use constants for column names

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixed incorrect SQL Count.

* Make SQL more readable.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-08 10:19:23 +00:00
Bjarne FyrstenborgandGitHub ac54cfd467 Property Editor Dialog: Set height to 100% for umb-property-editor-ui-picker-modal (#22354)
Set height to 100% for ui-picker-modal element
2026-04-08 12:04:08 +02:00
2f4d2351d0 Management API: Add document patch endpoint (#22104)
* Document patch, variant name only

* Multi variant tests

* Change to json-patch instead of merge to target nested properties

* Fix ManagementApiTest following PR 20820

* Segment suport for properties

* Verify non existing and trashed document patch behaviour

* Mostly working approuch for nested properties

* Fix endpoint route collision (Somehow...)

* Trying a custom way of doing things

* add escape support, more tests and cleanup

* remove unnecesary using

* Cleanup

* Restore things that are breaking

* cleanup

* Namespace cleanup

* Order cleanup

* More comment updates

* Add default implementations

* Improve modelbinding validation

* all string comparison

* Cleanup unused statuses

* Fix PatchPathResolver Filtering not accepting non string values

* Optimize path parsing

* Improve cookie token rework

* more cleanup

* Put AllowedValues on the correct property 🙈

* One more default implementation

* Add link to docs on endpoint swagger info

* PR review corrections

- Removed leftover affectedCultures & affectedSegments
- Extracted IDocumentPatcher interface
- Optimized serialization in patchEngine by moving it 1 level higher

* Update documentation urls

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Removed affected variance tracking that is nog longer being used

* Extract shared data class

* update claude patching namespace

* Remove no longer valid xml comment

* Fix unittests after refactoring patchengine.ApplyOperation(string,...) to patchengine.ApplyOperation(JsonNode,...)

* Refactor base classes

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Optimizations and refactoring of the patcher/engine/parser

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-08 11:55:22 +02:00
Andy Butland 3541b89380 Merge branch 'release/17.3.1' 2026-04-08 11:48:44 +02:00
530c861c2b Relations: Allow saving relation types without parent/child object types (closes #22359) (#22336)
* Allows save of a relation type without a child and/or parent object type.

* Addressed code review feedback and code health warnings.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-04-08 07:19:14 +00:00
Jacob Overgaard ff60c8c1a8 build(deps-dev): bumps package lock 2026-04-08 08:28:31 +02:00
Nhu DinhandGitHub c3f959f536 E2E: QA Added acceptance tests for bulk actions (#22361)
* Updated ui helper for select content card

* Updated ui helper for select media card

* Added ui helper for clear selection button

* Added tests for bulk action in list view content

* Added more tests for clear selection button in list view media

* Make tests run in the pipeline

* Reverted npm command
2026-04-08 04:58:30 +00:00
Nhu DinhandGitHub df3724c830 E2E: QA Remove @smoke tags from element tests (temporary) (#22363)
Temporary remove .smoke tags for the element-related tests
2026-04-08 09:29:06 +07:00
426eaf1ba9 Performance: Batch backoffice media thumbnail URL requests to reduce N+1 API calls (#22329)
* Batch thumbnail URL requests to avoid N+1 API calls.

* Handle code review feedback.

* Remove extra newlines.

* chore: formats code

* Use @consumeContext decorator and remove await #init from imaging repository.

Replaces the blocking `await this.#init` pattern with the `@consumeContext`
decorator so the store is consumed opportunistically. This removes the async
gap before batchImagingRequest calls, allowing all thumbnails mounting in the
same Lit render pass to be collected into a single batched API request.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Move imaging URL cache into the request batcher and deprecate UmbImagingStore.

The batcher now owns a module-level URL cache, eliminating the need for the
context-based UmbImagingStore. This removes all context-request events from
the imaging repository and thumbnail hot path. The repository delegates
entirely to the batcher for caching and fetching. UmbMediaDetailRepository
uses the new clearImagingCache() export directly instead of instantiating an
imaging repository. Items with no URL (non-image media) are cached as empty
strings to prevent unnecessary re-fetching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove extra newlines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 15:23:02 +00:00
Andy Butlandandkjac 6c089db898 Media Picker: Fix folder selection regression for developer-configured media pickers (closes #22349) (#22350)
* Fixes "files/folders/files or folders" selections for the various media picker components, re-allowing folder selection from a media picker.

* Import and use enim instead of hardcoded enum value

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-04-07 16:26:37 +02:00
Andy Butland 70dd464346 Builder Extensions: Make AddWebComponents() idempotent (closes #22344) (#22347)
Ensure AddWebComponents is idempotent.
2026-04-07 16:26:27 +02:00
dependabot[bot]andJacob Overgaard 3b69a2fffa Bump lodash from 4.17.23 to 4.18.1 in /src/Umbraco.Web.UI.Login
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-07 13:56:25 +02:00
e093ca5f49 Global Elements: Workspace UI updates: split view, variant selector, save modal, and pending changes (#21897)
* feat(elements): add contentTypeIcon observable and _handleSave override to workspace context

Adds contentTypeIcon observable, icon field to UmbElementDetailModel, and maps icon from server response. Adds _handleSave override to remap validation error colors to warning colors during save, matching Document workspace behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(elements): add loading state, variant selector, and cleanup to split view

Adds loading state observation and binding, variant selector slot with new element-specific variant selector component, and element sortVariants utility. Removes dead #breadcrumbs CSS rule and reorders splitViewIndex to match Document workspace conventions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(elements): wire up publishing workspace context in variant selector

Consumes UMB_ELEMENT_PUBLISHING_WORKSPACE_CONTEXT in the element variant selector, mirroring the Document pattern. Fixes PUBLISHED_PENDING_CHANGES localization to use the correct key.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(elements): add save modal for element workspace variant picker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Adds "Update" permission condition on Folder Rename entity-action

* feat(elements): add pending changes manager for element workspace

Mirror the Document workspace's UmbDocumentPublishedPendingChangesManager
to provide client-side comparison of persisted vs published element data.
The variant selector now uses this manager to determine pending changes
state instead of relying solely on the API state. The actual API call to
fetch published element data is left as a TODO until the backend endpoint
exists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update src/Umbraco.Web.UI.Client/src/packages/elements/modals/save-modal/element-save-modal.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/elements/utils.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(menu): delegate breadcrumb href to menu structure context

Move the href resolution logic from the breadcrumb element into the
menu structure workspace context via a new `getItemHref` method on the
interface and base class. This eliminates the need for duplicate
breadcrumb elements that only differ in href behavior, and mirrors the
existing pattern used by the variant breadcrumb.

* feat(elements): add menu structure context and breadcrumb for element folders

Add UmbElementFolderMenuStructureContext that overrides getItemHref to
make folder ancestors and the section root clickable in the breadcrumb.
Register the menu structure context and breadcrumb footer app in the
element folder workspace manifests.

* fix(elements): provide synthetic variant data for folder tree items

Folders don't have variants from the API, so provide a synthetic
published variant using the folder name. This prevents errors when
the tree item mapper expects variant data.

* Updates "umb-element-table-collection-view"

to add the column elements for "name" and (published) "state".

* Refactor exports in constants.ts for clarity

* fix(workspace): prevent breadcrumb TypeError for contexts without getItemHref

Menu structure contexts that don't extend the tree base class (e.g.
UmbLanguageNavigationStructureWorkspaceContext) lack getItemHref, causing
a runtime TypeError in the breadcrumb element. Use optional chaining to
gracefully handle missing implementations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(menu): add JSDoc to UmbMenuStructureWorkspaceContext interface

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-04-07 11:17:41 +02:00
bfa3c3234b Media Picker: Fix folder selection regression for developer-configured media pickers (closes #22349) (#22350)
* Fixes "files/folders/files or folders" selections for the various media picker components, re-allowing folder selection from a media picker.

* Import and use enim instead of hardcoded enum value

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-04-07 10:33:23 +02:00
Engiber LozadaandGitHub 80f864f298 Search: Show ancestor breadcrumb path in items results (closes #21107) (#22240)
* Show ancestor path in document search results.

* show ancestor breadcrumb path in media search results

* Show the document ancestors name by culture variant

* Extract ancestor fetching to reduce cyclomatic complexity

* Add early return inside #fetchAncestors

* Handle errors from the api call.

* Add fallback title when the name doesn't exist

* Use full item models for search ancestor types
2026-04-07 09:38:27 +02:00
Andy ButlandandGitHub cd541b66f4 Builder Extensions: Make AddWebComponents() idempotent (closes #22344) (#22347)
Ensure AddWebComponents is idempotent.
2026-04-07 07:07:19 +02:00
Andy Butland 8c5c6a8870 Install: Ensure media directory exists before creating PhysicalFileProvider (closes #14877) (#22281)
* Ensure media directory exists before creating PhysicalFileProvider.

* Ensure file provider is disposed in test.
2026-04-06 13:02:45 +02:00
Andy Butland 2b3f468111 Document URL Service: Batch delete of obsolete URL segment records to avoid SQL Server parameter limit (closes #22339) (#22340)
* Batch delete in DocumentUrlRepository and DocumentUrlAliasRepository to avoid exceeding SQL Server's 2100 parameter limit.

* Address code review feedback.

* Remove the unnecessary trigger rebuild on startup statement in the SQL Server migration path.
2026-04-03 12:38:49 +02:00
Andy Butland 727dd02a9e Bumped version to 17.3.1. 2026-04-03 11:35:54 +02:00
Andy ButlandandGitHub 5127b97e2c Document URL Service: Batch delete of obsolete URL segment records to avoid SQL Server parameter limit (closes #22339) (#22340)
* Batch delete in DocumentUrlRepository and DocumentUrlAliasRepository to avoid exceeding SQL Server's 2100 parameter limit.

* Address code review feedback.

* Remove the unnecessary trigger rebuild on startup statement in the SQL Server migration path.
2026-04-03 10:51:04 +02:00
b972d1db5a Global Elements: Element Tree Item "Draft" state (#22228)
* Adds "umb-element-tree-item" custom component

Updates context to use the item data resolver..

* Adds manifests for Element entity-signs

for "Has Pending Changes" and "Has Scheduled Publish"

* Update src/Umbraco.Web.UI.Client/src/packages/elements/tree/element-tree-item.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Attempt to fix the Item Data Resolver `setData` type-casting

* Align element tree item model with item model for type safety

Add required `flags` field to `UmbElementTreeItemModel` (via
`UmbEntityWithFlags`) and `UmbElementTreeItemVariantModel`, matching
the document tree pattern. This ensures the data resolver's `#setFlags()`
receives actual data instead of silently accessing undefined properties.

The `as unknown as` cast in the context remains due to nominal type
differences (entityType union, variant state enum) but is now structurally
safe at runtime.

* Maps `flags` in `UmbElementTreeItemVariantModel`

* Updated locator for element tree item due to UI changes

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Nhu Dinh <hnd@umbraco.dk>
2026-04-03 07:45:12 +00:00
Andy Butland 015d17db3f Merge branch 'main' into v18/dev 2026-04-02 08:19:35 +02:00
Andy Butland 9c309f6030 Merge branch 'release/17.3.0' 2026-04-02 07:41:44 +02:00
564068f61b Background Jobs: Fix period drift in RecurringHostedServiceBase (#22330)
* Compute next delay to compensate for time drift

* Addressed case flagged on code review following stopped service.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-02 05:19:26 +00:00
2a44169e0b Block Editors: Fix preset values for composition properties on non-varying element types (closes follow-up on #22320) (#22320)
Correct preset values for composition properties on non-varying element types

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-04-01 15:05:34 +00:00
20a8749b0c CLAUDE.md: OpenAPI.json maintenance (#22326)
* Added instructions for maintaining the `OpenApi.json` file

* Updated client-side instruction docs

for clean code and style guide.

* Updated "Full API surface" point

* Update CLAUDE.md

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-01 14:45:13 +00:00
Andy Butland af4a94a908 Bump acceptance test version to 17.3.0. 2026-04-01 16:18:04 +02:00
Andy Butland 0c30d86b25 Merge branch 'release/17.3.0' of https://github.com/umbraco/Umbraco-CMS into release/17.3.0 2026-04-01 16:15:47 +02:00
Andy Butland 55eda0832d Bump version to 17.3.0. 2026-04-01 16:15:31 +02:00
f8ba5db5aa Redirects: Fix crash seen in Redirect URL Management dashboard when the redirect route does not contain '/' (closes #22308) (#22309)
* Handle invalid redirect routes without slash in GetUrlFromRoute

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Handle fragment-only routes before parsing node id

* Add unit tests verifying the fix (as well as expanding the test coverage of the URL provider in general).

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-04-01 14:11:43 +00:00
Andy Butland 617f2441fc Merge branch 'main' into v18/dev 2026-04-01 15:39:23 +02:00
96766a80db Notifications: Surface ProblemDetails detail in error notifications (#22298)
* feat: surface ProblemDetails detail in error notifications

Pass the ProblemDetails detail field through to error notifications.
Short details (≤250 chars) are shown inline with CSS line-clamp.
Long details (>250 chars) are shown via a "See error" button that
opens the error viewer modal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review — rename detail/details ambiguity and remove as any cast

Rename local `details` variable to `errors` to avoid confusion with `detail`.
Change UmbErrorViewerModalData to a union type (UmbPeekErrorArgs | string)
matching what the modal actually handles at runtime, eliminating the as any cast.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: tighten types and overload _peekError with UmbPeekErrorArgs

- Document UmbPeekErrorArgs interface and its properties
- Add `errors` property to UmbPeekErrorArgs, deprecate `details`
- New _peekError overload: accepts UmbPeekErrorArgs directly
- Old _peekError overload: positional args, deprecated for removal in v19
- Update notification element and interceptor to use `errors`
- Widen UmbErrorViewerModalData to also accept Record<string, unknown>

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: extract duplicate errors fallback to #validationErrors getter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove unnecessary null handling in interceptor #peekError

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve tsc errors from type tightening

- UmbErrorViewerModalData: use Record<string, unknown> interface to
  satisfy UmbModalToken's object constraint (string not allowed)
- Cast detail string through unknown when opening error viewer
  (modal handles strings at runtime, token type doesn't allow it)
- Fix interceptor errors Record to use string[] values

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve eslint errors — unused import, prettier, jsdoc link

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: renames 'See error' button to 'Full Error Message'

* feat: renames Danish button 'Undtagelsesdetaljer' to 'Fejldetaljer'

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-01 13:59:36 +02:00
Niels Lyngsø c18f28d22d Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs
#	src/Umbraco.Core/Services/OperationStatus/UserOperationStatus.cs
2026-04-01 13:58:53 +02:00
3dc61fea80 Agent Review: Prefer documentation over implementations (#22324)
* Docs-first review: load prefs & validate patterns

* Update .claude/skills/umb-review/SKILL.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-01 11:42:53 +00:00
Mads RasmussenandGitHub 4f6a5b1c2d Backoffice: Add client-side model guidance and repo rules for agents (#22321)
* Add client-side model guidance and repo rules

* fix paths

* Update data-flow.md
2026-04-01 13:22:25 +02:00
Andy Butland f550eeec28 Fixed client-side build. 2026-04-01 12:36:20 +02:00
reabrandGitHub 7a5ed5ad00 Code Quality: Add 'new' keyword to 3 methods hiding inherited members resolving CS0114 warnings (#22317)
* Fix CS0114: Add 'new' keyword to 3 methods hiding inherited members

* docs: update TODO comments for 'new'/'new virtual' methods (V18 cleanup)

* docs: update TODO comments for 'new'/'new virtual' methods (V18 cleanup)
2026-04-01 11:38:15 +02:00
Andy ButlandandGitHub 63fff17759 BlockGrid: Protect against null columnSpan/rowSpan when rendering blocks (closes #22306) (#22311)
* Protect against null column or row span when rendering blocks.

* Addressed code review feedback.
2026-04-01 10:52:21 +02:00
Andy Butland 22907e01ef Updated OpenApi.json. 2026-04-01 09:54:54 +02:00
59a7d99e3c Elements: Add PublishedCultures and UnpublishedCultures to ElementCacheRefresher (#22302)
* Add PublishedCultures and UnpublishedCultures to ElementCacheRefresher.JsonPayload

Adds culture-specific publishing details to the element cache refresher payload,
matching the existing ContentCacheRefresher.JsonPayload structure. Also replicates
the performance optimization from #21415 by only clearing partial view cache when
there are actual publish/unpublish culture changes, and fixes the Remove change
type check to use HasType instead of equality (flags enum).

* Reuse content cache logic for partial view cache clearing

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-04-01 09:27:33 +02:00
1b15f51798 Backoffice: Add Repository documentation and create-repository skill for agents (#22310)
* Add workspaces docs, CLAUDE link, and skill

* Export workspace elements as element

* consolidate information

* adjust skill to make use of generic name component

* try to force the agent to follow docs and use skills

* Update SKILL.md

* clean up create package skill

* use data type package as reference

* add initial repository doc + skill

* Update src/Umbraco.Web.UI.Client/docs/workspaces.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/docs/workspaces.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update workspaces.md

* clean up

* Update SKILL.md

* Delete Repositories.md

* Create repositories.md

* Update repositories.md

* Normalize repositories doc links to lowercase

* Update src/Umbraco.Web.UI.Client/.claude/skills/general-create-repository/SKILL.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix data flow link path casing

* fix casing

* export as api + inline store in manifest

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-01 09:26:38 +02:00
Niels Lyngsø f4b3a0f4ac update management api types 2026-04-01 09:19:47 +02:00
43ccd7a171 Application URL: Add ApplicationUrlDetection setting to control application URL auto-detection (#22307)
* Prevent Host header poisoning of ApplicationMainUrl.

* Introduce options for Umbraco application URL detection and handle situations where it can be undefined.

* Prevent email operations if the application URL is not detected or configured.
Improve log warnings.

* Addressed feedback from code review.

* Move startup application URL logging to a handler.

* Clean up ambiguous log message

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-04-01 09:18:43 +02:00
Niels Lyngsø 68d9e02417 Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Cms.Api.Management/OpenApi.json
#	src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts
2026-04-01 09:13:55 +02:00
6e85871595 Global Elements: Recycle Bin UI (#21872)
* Uncommented placeholders for restore endpoints

* Delete (inside Recycle Bin): wired up correct endpoints

* Added condition for "Empty Recycle Bin" collection-action

to only display in the Recycle Bin root.

* feat(recycle-bin): add destination entity overrides to restoreFromRecycleBin kind

Add optional destinationItemRepositoryAlias, destinationItemDataResolver,
and destinationRootEntityType properties to support cross-entity-type
restore (e.g. element restoring into element-folder). Existing document
and media manifests are unaffected as all new properties fall back to
the original values. Also adds element folder restore manifest.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(recycle-bin): extract #resolveDestinationItemName to reduce complexity

Extract resolver logic from setDestination into a dedicated method to
bring cyclomatic complexity under the threshold of 9.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Removed Restore Element Folder From Recycle Bin Entity Action

(This is for a separate PR)

* feat(elements): enable element and folder restore from recycle bin

Uncomment element restore manifest with destination overrides, add
folder picker modal, and add null guard for restore item lookup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fixes bug with selecting the Root for the restore target

* Corrected manifest aliases to use appropriate entity-type name for `ElementFolder`

* Added `UmbElementFolderItemDataResolver` to resolve folder names in recycle bin restore modal

* E2E: QA Added acceptance tests for restoring elements and deleting elements from recycle bin (#22069)

* Updated test helper for move a folder to recycle bin

* Added tests for restore element and delete element from recycle bin

* Added ocmment for the failing tests

* Make recycle bin tests run in the pipeline

* Fixed comment

* Removed duplication code

* Reverted npm command

* Adds `itemDataResolver` to the Element Trash entity-action

* Makes trashed Element Folder name to be read-only

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-04-01 09:01:05 +02:00
Andy ButlandandGitHub 6853f2c910 EF Core: Align casing of EF Core code constructs (closes #22247) (#22313)
* Align casing of EFCore code constructs.

* Handle code review feedback.
2026-04-01 06:56:48 +02:00
3b0972cd56 Document Blueprints: Add info workspace view (#21951)
* add info workspace view  into document blueprint

* Add history panel

* update document type route

* remove comment

* move time options format to ultils

* add blueprint auditlog model

* save move action and add authorization for audit log request

* add default implement

* update open api json

* Reused the `workspaceInfoApp: auditLog` kind

Added the manifest for the repository.
Removed the duplicated/unused code.

* UI tweaks + linting

* Renamed "Document Blueprint Workspace View Info Element" file/tag

* Restored the "UmbDocumentBlueprintAuditLog" types

* Add JSDoc to document blueprint audit log repository

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Export audit-log module from document-blueprints index

Adds the missing re-export so UMB_DOCUMENT_BLUEPRINT_AUDIT_LOG_REPOSITORY_ALIAS
is reachable from @umbraco-cms/backoffice/document-blueprint.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: leekelleher <leekelleher@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-03-31 15:51:34 +00:00
Andy ButlandandGitHub 5d17ead9db Build: Pin CycloneDX SBOM generation to spec version 1.5 (#22305)
Pin dotnet-CycloneDX to spec-version 1.5
2026-03-31 14:46:53 +00:00
021163f100 Review: Claude Skill for Review of Github PRs (#22245)
* claude review md files

* rename to review

* auto-detect target-branch via GH CLI

* Verify GH CLI is Available

* update table to fit github markdown format

* condensed the output to the essense

* State if the PR is too bad

* using the word `and´

* only relevant suggestions

* clean up

* narrow the scope for large PRs

* diff-first approach with selective reads

* specify that the header_only are amount of file where the only extra loaded is the header

* Complexity detection

* Classification of the PR

* improve other changes

* Ensure Types are kept intact in their type Hierarchy

* align test naming with project, and clean up instructions

* remove hardcoded Claude.md file table for a pattern

* improve skill description

* improved breaking change detection for front-end

* do not suggest breaking changes for PRs targeting main

* rename skill to umb-review

* less nit picky

* first version of skill evals

* Update .claude/skills/umb-review/references/coding-preferences.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update .claude/skills/umb-review/references/impact-analysis.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* remove mentioning the skill action it self

* split out GH CLI guideline

* improve file loading strategy

* make feedback extremely concise

* improve skipped files output

* latests eval

* added further evals

* move summaries into references

* separate Complexity Assessment into a reference file

* Complexity Assessment: secure mixed is still check despite other rules it out

* dont include gen.ts files

* iter 9 evals

* latests eval of 4

* keep only one test for complexity-advisory

* adjusted skill and Evals to match expectations

* improve sibling lookups

* improve skill regarding nit picks and C# patterns

* remove insecure manifest check

* final eval run

* eval grading

* remove review workspace

* remove umb review workspace part 2

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-31 12:36:34 +02:00
Andy Butland 9d94b26cc2 Merge branch 'main' into v18/dev 2026-03-31 12:12:57 +02:00
33bf627602 Backoffice: Add Workspace documentation and create-workspace skill for agents (#22300)
* Add workspaces docs, CLAUDE link, and skill

* Export workspace elements as element

* consolidate information

* adjust skill to make use of generic name component

* try to force the agent to follow docs and use skills

* Update SKILL.md

* clean up create package skill

* use data type package as reference

* Update src/Umbraco.Web.UI.Client/docs/workspaces.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/docs/workspaces.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update workspaces.md

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-31 11:21:50 +02:00
Nhu DinhandGitHub 851cc79d2c Build: Publish test helper to Myget (#22156)
* Publish test helper to Myget

* Moved acceptance-test-helper to umbraco-cms

* Updated scope
2026-03-31 09:04:21 +00:00
81ef90dd27 BackOffice Document Editing: Fix pending changes status in variant selector (closes #22271) (#22290)
* Present only changed variants as selected by default when saving and publishing.

* Detect pending changes on document load to ensure language selector variant status reports correctly.

* Avoid concurrent loads.

* Fix issue where with two variants changed but only one saved, both would display with pending changes.

* Addressed code review feedback.

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-03-31 09:42:51 +02:00
Andy ButlandandGitHub 2e23ca5599 Performance: Optimize ContentTypeRepository deep-clone on cache reads (closes #22250) (#22263)
* Optimize ContentTypeRepository to avoid unnecessary deep-cloning on cache reads.

* Used lightweight benchmark and addressed code review comments.
2026-03-31 09:38:33 +02:00
58cbc9790f Global Elements: Adds "Start Node" and "Ignore User Start Nodes" to Element Picker configuration (#22255)
* Element Picker property-editor: adds "Start Node" configuration

* [WIP] Adds server config for Element start node

* [WIP] Attempts to wire up the `dataTypeId`

for the Element Picker start node

* Removed `StartNodeId` from the server config

* Implemented `requestTreeStartNode`

on Element Picker data-source

* Fix duplicate config entries in input-element property setters

The `folderOnly` and `startNode` setters used `.push()` without
deduplication, causing config entries to accumulate on Lit re-renders.
Filter existing entries before pushing to prevent duplicates.

* Update OpenAPI spec and regenerate TypeScript bindings

Add dataTypeId query parameter to element tree endpoints.

* Refactor input-element to compute dataSourceConfig on demand

Replace mutable #dataSourceConfig array with plain Lit properties for
folderOnly and startNode, computing the config inline in render. This
eliminates the duplicate-entry bug and simplifies the component.

Also fix "dont" typo in ignoreUserStartNodes description.

---------

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2026-03-31 08:11:06 +01:00
8311bae2ab User Permissions: Resolve and persist element start node IDs when updating a user (#22297)
* Resolve and persist element start node IDs when updating a user

The UpdateAsync method in UserService only resolved Document and Media
start node keys to IDs, completely ignoring ElementStartNodeKeys from
the update model. This caused element start node configuration to be
silently lost on user save.

* Add ElementStartNodeNotFound status and fix XML doc for MapUserUpdate

Introduces a dedicated ElementStartNodeNotFound operation status to
distinguish missing element start nodes from missing element items in
other operations, consistent with ContentStartNodeNotFound and
MediaStartNodeNotFound. Also adds the missing XML doc param for
startElementIds on MapUserUpdate.

* Add blank line to re-trigger the build.

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-03-31 07:26:58 +02:00
2bfb83d6f7 Global Elements: Add "Allowed in library" toggle to Document Type structure view (#21875)
* Added localization keys

* Fixed mock data

* Adds UI for "Allowed in library" configuration

* Capitalize nouns regarding allow in library

* Focuses `allowedInLibrary` on Document/Element Types

* refactor(web): extract route setup from UmbDocumentTypeWorkspaceContext constructor

Move route configuration into a private #setupRoutes() method to reduce
constructor cyclomatic complexity below the threshold of 9.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Claude <noreply@anthropic.com>
2026-03-30 17:46:13 +01:00
c19e424cdd Tiptap RTE: Add width/height to edit image properties (AB#65981) (#22266)
* TipTap: Add width/height to edit image properties (AB#65981)

Add width and height input fields with aspect-ratio lock toggle to the
media caption/alt-text modal. Thread dimensions through the toolbar
action so existing image dimensions are preserved when editing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* TipTap: Add double-click to open edit modals for images and embeds

Move double-click detection into node extensions via addProseMirrorPlugins
(tiptap-native). Extensions dispatch a generic DOM event, input-tiptap
delegates to the toolbar, and the toolbar executes the active action.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* TipTap: Improve edit image properties, unify embed dimensions, fix figcaption bug (AB#65981)

- Add width/height fields with aspect-ratio lock and maxImageSize cap to image modal
- Unify embed modal dimensions UI with image modal (inline row, lock button, px postfix)
- Fix figcaption cursor bug: editing from inside caption no longer opens new image picker
- Pass user dimensions to imaging endpoint for valid HMAC-signed URLs
- Preview image updates aspect-ratio when dimensions change
- Slim down toolbar API: inline pass-through methods, remove dead code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add missing width: 100% to image modal dimension inputs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use display:block instead of width:100% on dimension inputs

Prevents the right border of the px affix from being clipped.
Applied to both image and embed modals for consistency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove explicit sizing on dimension inputs, let flex handle it

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use @input instead of @change on embed dimension fields

Aligns with image modal behavior so constrained dimensions update
on keystroke. Preview fetch is debounced at 500ms to avoid spam.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address Copilot review feedback

- Wrap imageSize() in try/catch so modal remains usable on broken URLs
- Recalculate aspect ratio on re-lock in image modal (matches embed)
- Change min="0" to min="1" on dimension inputs (both modals)
- Fix constrain truthiness check to use !== undefined

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* TipTap: Use maxImageSize config for embed defaults, update ratio to 16:9

Replaces hard-coded 360x240 (3:2) embed defaults with maxImageSize from
RTE config and a 16:9 aspect ratio matching modern video embeds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: select figure before replacing when editing from figcaption

When cursor was inside a figcaption, insertContent would insert a new
figure at the cursor instead of replacing the parent figure. Now selects
the figure node via setNodeSelection before proceeding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: export UMB_TIPTAP_NODE_DBLCLICK_EVENT from tiptap constants

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: removes double-click handling (to be implemented later on)

* Apply suggestion from @AndyButland

Co-authored-by: Andy Butland <abutland73@gmail.com>

* feat: adds constants for default width and height and guards against 0-values

* feat: validates that width and height are larger than 1px

* refactor: Extract shared <umb-input-dimensions> component

Deduplicates the width/height dimension input logic that was repeated
in both the media caption/alt-text modal and the embedded media modal.

The new component supports aspect ratio locking, proportional resize,
disabled state, and an optional reset-to-natural-dimensions button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: embeds should be constrained by default

* feat: defaults embed constrain to true

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: always fetch natural dimensions so reset button appears when editing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: move reset button below dimensions and cap natural size to maxImageSize

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: cleanup

* fix: use general_clear localization key for reset button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: constrain embed preview to sidebar width using aspect-ratio

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: target any first-child element in embed preview, not just iframe

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add comment explaining generic selector for oEmbed markup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use height auto to let embed scale naturally from width

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use !important on width to override inline oEmbed attributes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use height 100% so iframe fills the aspect-ratio container

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: smooth embed preview aspect-ratio changes with CSS transition

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: smooth image preview aspect-ratio changes with CSS transition

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: show Clear button on embed dimensions using default size as natural

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: use maxImageSize for embed natural dimensions and Clear button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: media-with-caption modal should be 'medium'

* feat: address review feedback on dimensions and preview

- Rename reset button label from general_clear to general_reset (new key)
- Fix embed preview: use pixel width + aspect-ratio + max-width for
  accurate proportional preview at any dimension
- Apply same width+aspect-ratio approach to image preview
- Add uui-box to media caption modal for consistent sidebar background
- Center image and embed previews in their containers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: simplify embed modal — honest dimensions, responsive iframe preview

Remove maxImageSize and naturalWidth/naturalHeight from embed modal since
oEmbed dimensions are hints (maxwidth/maxheight), not guarantees. Add
localized description explaining this to the user. Fix iframe preview
collapsing to 150px by reading width/height attributes and applying
aspect-ratio via JS (iframes lack intrinsic dimensions unlike images).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: recalculate aspect ratio when dimensions are set externally

When width/height properties are set from outside (e.g. after async
imageSize() resolves), the ratio was not recalculated — leaving it
undefined from connectedCallback. This caused locked mode to silently
fail on first appearance of the media caption/alt-text modal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-30 15:08:31 +00:00
Laura NetoandGitHub f1a7c6bbc1 Localization: Remove unused recycleBin keys from XML language files (#22299)
Remove unused recycleBin keys from XML language files

The recycleBin area contained keys (contentTrashed, mediaTrashed,
elementTrashed, elementContainerTrashed, itemCannotBeRestored,
itemCannotBeRestoredHelpText, wasRestored) that are no longer
referenced by any backend code since the audit logging was removed
from RelateOnTrashNotificationHandler in #21481.
2026-03-30 17:04:34 +02:00
b79639cb23 Document Editing: Fix unchanged variants selected in save and publish dialog (closes #22277) (#22285)
Present only changed variants as selected by default when saving and publishing.

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-03-30 14:00:51 +00:00
934834b6f5 Rich Text Editor: Filter paste, drag&drop, and media picker to allowed media types (closes #21824) (#22267)
* RichTextEditor: Filter media picker to allowed media types (closes #21824)

Add allowedMediaTypes config to the RTE data type, filtering the media
picker tree to only show selectable media types. Also applies type-aware
validation to drag-and-drop uploads using UmbMediaTypeStructureRepository,
with a modal picker when multiple types match a dropped file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Review fixes: cache media type lookups, remove unnecessary localization keys, fix lint

- Cache requestMediaTypesOf results per extension to avoid redundant API calls
  when dropping multiple files with the same extension
- Add try/catch around API call to prevent unhandled rejections from crashing
  the upload loop
- Remove custom localization keys, reuse same plain strings as MNTP config
- Fix prettier formatting warnings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Auto-Pick in media type picker modal no longer silently fails

The modal returns `{ mediaTypeUnique: undefined }` for auto-pick, which
was treated as a cancellation. Now distinguished from cancel (rejected
promise) and falls back to the server's preferred type.

Fixed in both the media dropzone manager and TipTap drag-drop upload.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: Add localization keys for allowedMediaTypes config, reorder weight

Move allowedMediaTypes next to mediaParentId (weight 91) as they are
related media config options. Use #rte_config_* localization pattern
matching other RTE config properties.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Show notification when pasting disallowed file types into RTE

The MIME-type pre-filter silently dropped non-image files on paste
(and drag-drop). Now shows the same disallowed file type notification
as the media type validation path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: Add server-side validation for RTE AllowedMediaTypes config

Validates that media items referenced via data-udi in RTE markup are of
an allowed media type. Follows the same pattern as MNTP's
AllowedTypeValidator. Includes unit tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Clean up validator tests: remove unused param and region markers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Use splitStringToArray for config parsing consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Include media name in validation error for disallowed media types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: Fix and add acceptance tests for RTE allowedMediaTypes config

* feat: Default RTE to Image and SVG allowed media types

Set allowedMediaTypes to Image and Vector Graphics (SVG) in the
default Rich Text Editor data type seed for new installs. Also
update the Vite mock data to match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Address Copilot review feedback

Fix test helper that swallowed null allowedMediaTypes parameter,
masking the "no filter configured" test case.

Remove redundant upload failure toast that showed a misleading
"disallowed media type" message for non-validation failures
(the upload manager already handles its own error notifications).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Use constants for seed GUIDs, normalize file extension casing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Refactored media type checks into helper shared across RTE and media picker.
Resolved case insensitivity edge case.
Removed unnecessary obsolete constructor.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-30 14:17:55 +02:00
4d993a6dd1 Elements: Add flag support for pending changes and scheduled publish (#21877)
* Add flag support for pending changes and scheduled publish

Add entity sign manifests, tree item rendering, and flag provider
support so element tree items display pending changes (pencil) and
scheduled publish (clock) icons, mirroring the existing document
behavior.

Refactor flag providers and presentation factories to reduce
duplication, and move shared IHasFlags implementation into
PublishableVariantResponseModelBase.

* Fix HasScheduleFlagProvider test mocks to match refactored per-item lookups

* Extract PublishableVariantItemResponseModelBase to deduplicate variant item models

* Extract shared base class from Document/Element presentation factories

Introduce PublishableContentPresentationFactoryBase to eliminate code
duplication between DocumentPresentationFactory and ElementPresentationFactory.
Add async alternatives (CreateVariantsItemResponseModelsAsync,
CreateItemResponseModelAsync, PopulateFlagsAsync) and migrate callers in
async contexts to use them. Sync callers in tree/recycle bin controllers
use .GetAwaiter().GetResult() to avoid breaking changes in base classes.

Add IPublishableContentEntitySlim overload to DocumentVariantStateHelper
to unify the identical IDocumentEntitySlim/IElementEntitySlim overloads.

Make RelationTypePresentationFactory properly async with Task.WhenAll.

* Fix flags fallback to use empty array instead of empty string

* Acceptance Tests: Fix element tree item locator to match both elements and folders

The element tree renders umb-element-tree-item for elements but
umb-default-tree-item for folders. Update the E2E test helper locator
to use :is() to match both custom element types.

* Split HasScheduleFlagProvider into document and element providers

Address PR review feedback:
- Split HasScheduleFlagProvider into HasDocumentScheduleFlagProvider and
  HasElementScheduleFlagProvider with a shared HasScheduleFlagProviderBase
- Fix N+1 query: use batch GetContentSchedulesByKeys instead of per-item
  GetContentScheduleByContentId
- Add GetContentSchedulesByKeys to IPublishableContentService and implement
  in PublishableContentServiceBase, removing the duplicate from IContentService
  and ContentService
- Inject TimeProvider into base class, replacing DateTime.Now with
  _timeProvider.GetUtcNow()
- Split tests to match new provider structure and verify batch retrieval

* Make tree and recycle bin mapping methods async

Remove .GetAwaiter().GetResult() calls introduced by the element flag
support changes. Rename MapTreeItemViewModel to MapTreeItemViewModelAsync
and MapRecycleBinViewModel to MapRecycleBinViewModelAsync across all
tree and recycle bin controllers, properly awaiting async factory calls.

* Extract Task.WhenAll select expressions into named variables

* Add missing XML docs to async methods on IDocumentPresentationFactory

* Fix DateTime vs DateTimeOffset comparison in schedule flag provider

Compare schedule.Date against _timeProvider.GetUtcNow().UtcDateTime
instead of the DateTimeOffset directly, avoiding implicit conversion
issues with DateTimeKind.Unspecified.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-30 12:54:37 +02:00
Mads RasmussenandGitHub 0bf0634d4f Templating: Add Production Mode condition to Partial View and Template Collection create actions (#22295)
Add production-mode condition to collection actions
2026-03-30 12:24:31 +02:00
c765ce6066 Accessibility: Include visible initials in name displayed on account menu button (closes #21942) (#22117)
* Fixed label in account menu button

The account menu button in the backoffice header was displaying user initials
visually (e.g., "AB") but the accessible name only showed "Profile options",
violating WCAG 2.5.3 which requires that when a UI component has visible text,
the accessible name must contain that visible text.

This fix ensures voice navigation software (e.g., Dragon NaturallySpeaking) can
properly recognize commands using the visible initials.

Changes:
- Added getInitials() utility function to extract first and last initial from user names
- Updated current-user-header-app component to include user name and initials in the
  button's accessible label (aria-label)
- Updated profileOptions localization term in all 15 language files to include
  placeholders for user name and initials using %0% and %1% format

Result:
- Visual display: "AB"
- Accessible label: "User profile for Andreas Lykke Borg (AB)"

The visible initials are now included in the accessible name, providing a
consistent experience for all users including those using assistive technologies.

Fixes #21942

* Update src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/get-initials.function.ts

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Added a fallback profile options label if name is null or empty

* Added test for get-initials function

* Added note about duplicate get-initials function

* Replicated the logic from the UUI avatar

* Add TODO to use utility exposed from UUI library for extracting the initials.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-30 07:30:07 +00:00
Andy ButlandandGitHub 71d9e34f20 Install: Ensure media directory exists before creating PhysicalFileProvider (closes #14877) (#22281)
* Ensure media directory exists before creating PhysicalFileProvider.

* Ensure file provider is disposed in test.
2026-03-30 14:56:24 +09:00
Andy ButlandandGitHub dbb492b6e8 User Service: Fix WhereIn subquery in PermissionRepository (closes #22288) (#22289)
* Correct WhereIn subquery in PermissionRepository.

* Addressed code review feedback.

* Relocated tests to permission specific file.
2026-03-30 14:01:07 +09:00
Jose MarcenaroandGitHub 753976bdcc User management: Show change password validation error (closes #22291) (#22292)
Fixes #22291

In order to show the right validation message:

 - the repository code always notifies the validation failure message
    (or a default failure message if none is received)
 - in the data-source code, tryExecute is called with the option
    to disable the default notification

Return the original error instead of faking success
2026-03-30 06:36:50 +02:00
Andy Butland 950470aade Make long-running concurrent save test more robust. 2026-03-28 17:01:11 +01:00
6b9bd4c787 Media: Allow duplicating system media types (closes #22282) (#22284)
* Allow copying of system media types.

* feat: Improve error message for system media type alias change

Replace the generic "Operation not permitted" error with a specific
"Alias change not permitted" message that explains the constraint and
suggests using the duplicate operation instead.

Also adds an ordering comment in DeepCloneWithResetIdentities and
a test assertion verifying the copy's alias is mutable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 17:40:39 +00:00
Andy Butland 581c3ec64d Merge branch 'release/17.3.0' 2026-03-27 15:03:25 +01:00
Andy Butland 65a89244f0 Unattended Upgrades: Rebuild routing caches after background migrations to fix unroutable document URLs (#22269)
* Prevent HybridCache from caching null content entries.

* Revert change and use approach of ensuring null cached values are tagged.
2026-03-27 13:49:24 +01:00
Andy ButlandandGitHub 1cde598ded Unattended Upgrades: Rebuild routing caches after background migrations to fix unroutable document URLs (#22269)
* Prevent HybridCache from caching null content entries.

* Revert change and use approach of ensuring null cached values are tagged.
2026-03-27 13:46:40 +01:00
400fd5b0e0 Backoffice Agent Context: Add design philosophy, developer roles and skills for a few common extensions and infrastructure tasks (#22273)
* add frontend claude context for architecture, deprecation, package-development

* update with developer roles

* tighten up for llm consumption

* add information about localization

* add section about kinds

* include test priority

* add llm docs for core primitives and data flow

* add info about caching

* add skills

* organize in folders

* flat list of skills

* Update src/Umbraco.Web.UI.Client/docs/architecture.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/docs/package-development.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* update skill name

* format tech stack based on claude recommendations

* add context about entities

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-27 12:35:53 +01:00
a69ce5df2f Backoffice: Remove token cookie if decryption fails (mitigates #16107) (#22237)
* Remove token if decryption fails

* Update src/Umbraco.Cms.Api.Common/DependencyInjection/HideBackOfficeTokensHandler.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* inlcude namespace for suggested code change

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-27 12:02:39 +01:00
7f1255b5e7 Content Types: Granular content type change types (#22223)
* Add more granularity to ContentTypeChangeTypes and handle for structucal changes (pending non-structucal changes).

* Integration tests to validate the granular, structucal change types

* Implement "other" changes

* Make "other" changes less granular.

* Update tests/Umbraco.Tests.Integration/Umbraco.Core/Services/ContentTypeEditingServiceTests.ChangeTypes.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Clean up

* Add test proving the sub-flags do not collide

* Support change detection for both structural and non-structural changes in one operation

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-27 09:55:35 +01:00
Andy Butland 6f152eae64 Migrations: Fix NPoco auto-select breaking retrust FK migration (#22270)
Prevent NPoco auto-select from breaking retrust migration.
2026-03-27 09:35:47 +01:00
Andy ButlandandGitHub dd7fb87534 Migrations: Fix NPoco auto-select breaking retrust FK migration (#22270)
Prevent NPoco auto-select from breaking retrust migration.
2026-03-27 09:17:52 +01:00
6e27ab2e0a Elements: Add missing notifications to element container and element editing services (#22012)
Add missing notifications to element container and element editing services

Add ElementDeletingNotification and ElementTreeChangeNotification to
ElementContainerService for EmptyRecycleBin, Move, MoveToRecycleBin,
and Delete operations, aligning with ContentService notification patterns.

Add ElementTreeChangeNotification to ElementEditingService for Move
and Copy operations.

Refactor DeleteDescendantsLocked to return deleted elements and
DeleteItem to return the deleted entity for use in tree change
notifications.

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-27 08:55:59 +01:00
Andy Butland da614e7d2c Fixed integration tests failing on SQL Server and NUnit 4. 2026-03-27 08:26:18 +01:00
Andy Butland a619182bae Dependencies: Update Microsoft packages to latest patch and fix HybridCache ParseFault with Redis (#22278)
* Update Microsoft.Extensions.Caching.Hybrid to latest minor, and other Microsoft dependencies to latest patch.

* Align test and local web project dependency versions.
2026-03-27 06:29:06 +01:00
4940b28cc3 Tests: Remove dead KeepAlive config remnants (#22272)
chore(tests): remove dead KeepAlive config remnants

The KeepAlive feature was removed in b619399edb (#15891) but references
to the config remained in 8 acceptance test appsettings.json files and
2 CI pipeline env var definitions. These are no-ops since the setting
no longer exists — remove them.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2026-03-27 04:27:55 +00:00
Andy ButlandandGitHub 0c294fb8bc Dependencies: Update Microsoft packages to latest patch and fix HybridCache ParseFault with Redis (#22278)
* Update Microsoft.Extensions.Caching.Hybrid to latest minor, and other Microsoft dependencies to latest patch.

* Align test and local web project dependency versions.
2026-03-27 08:09:03 +09:00
Andy Butland 858c450223 Merge branch 'main' into v18/dev 2026-03-26 16:51:27 +01:00
e8f5b98cb0 Code Clean-up (18): Remove obsoleted code flagged for removal (Part 2) (#22137)
* Remove obsolete code

* Update tests in BlockEditorBackwardsCompatibilityTests

* update languageId, remove obsolete construcor from ApiLink

* remove the tests

* Fixed build of unit tests.

* Reverted removal of UmbracoApiController for now (we should do this in a single PR).

* Code style fix.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-26 15:08:10 +00:00
a03fb9b0e3 Media: Set width and height for uploaded SVGs (#22244)
* Added migration for SVG width/height

* #22114 worked on SVG width height implementation

* #22244 Code style fixes

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 XmlReaderSettings and using

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Cleanup

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Correction if statement

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Refactor log message

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Correction if statment

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Cleanup

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Cleanup

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Code style adjustments

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Adjust if statement

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Adjust documentation comments

Co-authored-by: Andy Butland <abutland73@gmail.com>

* #22244 Fix log comment

* #22244 Fallback to viewbox if width height attribute has other unit than numeric or px.

* #22244 Refactoring SVG parser, no support for decimals

* #22244 Migration, consistent logging

* #22244 Create vector umbracoWidth and umbracoHeight during clean install

* #22244 Remove SupportedImageType from ISvgDimensionsExtractor

* #22244 pass culture and segment to SetValue

* Add DtdProcessing.Prohibit security hardening to SvgDimensionExtractor.

* Addressed some code styling and robustness of the migration and extractor classes.

* Add further unit tests.

* Add logging to notification handler. Skip when properties don't exist to avoid unnecessary processing.

* Add unit tests for media saving handler.

* Move the dimensions extractor implementation into infrastructure.

---------

Co-authored-by: Markus Johansson <markus@obviuse.se>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-26 15:34:28 +01:00
867414629b Cache sync: append SiteName to machine identifier for same-host load balancing (#22257)
* fix(core): append SiteName to machine identifier for same-host load balancing

When multiple Umbraco instances run on the same machine (e.g. IIS AAR load
balancing or local LB simulation), they shared the same machineId key in the
umbracoLastSynced table, causing cache sync interference. If Umbraco:CMS:Hosting:SiteName
is configured, it is now appended to the machine name to produce a unique
identifier per instance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update tests/Umbraco.Tests.UnitTests/Umbraco.Core/Factories/MachineInfoFactoryTests.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Validate length

* Refactor to enable us to have a validator

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-26 10:00:26 +01:00
b292535cf9 Repositories: Fix Raw Sql Statements without Escaped Table, Column or Alias Names (closes #22259) (#22261)
* fix raw sql statements without escaped table, column or alias names.

* fix more raw sql statements without escaped table, column or alias names.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Improve variable naming.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-26 08:47:15 +01:00
Nhu DinhandGitHub 3238f2306a E2E: Added acceptance tests for block grid area (#22181)
* Added api helper for block grid area

* Updated ui helper for block grid area

* Updated tests for block grid area

* Updated json builder for blockGridSpecifiedAllowance

* Formatted code

* Updated ui helper for specifiedAllowance

* Updated tests

* Fixed ui helper for enterSpecifiedAllowanceMinByIndex

* Added ui helper for create content with a block area with specified allowance

* Added tests for create content with ablock grid area with specified allowance

* Format code

* Make tests run in the pipeline

* Fixed tests

* Fixed comments

* Reverted npm command
2026-03-26 05:44:27 +00:00
Andy ButlandandGitHub bb44bed058 Examine Dashboard: Support content node links from delivery API index (closes #22221) (#22225)
* Support link to document from backoffice examine index view for delivery API index.

* Address PR feedback.
2026-03-26 12:24:03 +09:00
5f684eaa10 Content Version Cleanup: Optimize for large datasets (closes #22224) (#22239)
* Extend and tidy up unit and integration test coverage.

* Add MaxVersionsToDeletePerRun configuration setting.

* Added overload to GetDocumentVersionsEligibleForCleanup to allow restricting results to older than a given date and with a maximum count.

* Use SQL date filter and per-run cap in content version cleanup.

* Handle deletes using optimised process using temp tables.

* Make maxCount nullable and add per-run cap integration test.

* Addressed code review feedback.

* Fix to reporting of cap reached.

* Additional unit tests for max date cut-off logic.

* Add TODOs for removal of default implementations from interfaces.

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>

* Revert timing for ContentVersionCleanupJob.

* Add index to versionDate on umbracoContentVersion.

* Ensure long command timeout for upgrade.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-03-25 13:31:04 +01:00
Mads RasmussenandGitHub 2f7f8cf905 Backoffice: Fix Ctrl+C not terminating the example dev server (#22249)
Close readline before starting dev server

Close the readline interface before launching the Vite dev server so Ctrl+C can properly terminate the process.
2026-03-25 09:44:36 +00:00
Nhu DinhandGitHub 339da5e19e E2E: V18 Fixed the failing smoke tests (#22248)
* Reverted fix

* Updated tests regarding duplication due to UI changes
2026-03-25 09:35:40 +00:00
Nhu DinhandGitHub 29f267338c E2E: Reverted npm command for smokeTest (#22246)
Reverted npm command for smokeTest
2026-03-25 09:03:51 +00:00
Andy Butland 9ef7c5b955 Further fix to failing acceptance test. 2026-03-25 08:37:35 +01:00
Andy Butland ad8db9c567 Fixed failing integration and acceptance tests after merge. 2026-03-25 06:51:24 +01:00
Andy Butland 949584afc2 Examine: Fix DocumentUrlService not initialized during Examine indexing after package upgrade (#22243)
* Revert to segment retrieval from content when document URL service isn't initialised.

* Add tests for ContentValueSetBuilder.
2026-03-25 06:29:40 +01:00
Andy Butland 9a7c8efbd0 Bump version to 17.3.0-rc3. 2026-03-25 06:29:23 +01:00
Andy ButlandandGitHub cef63cb07d Examine: Fix DocumentUrlService not initialized during Examine indexing after package upgrade (#22243)
* Revert to segment retrieval from content when document URL service isn't initialised.

* Add tests for ContentValueSetBuilder.
2026-03-25 06:25:41 +01:00
Nhu DinhandGitHub 276d12d963 E2E: QA Added acceptance tests for validating a mandatory multi URL picker (#22235)
* Added more constant variable for validation message

* Added api helper for creating multi url picker data type with min number

* Renamed

* Updated api helper for creating document with multi url picker

* Added tests for mandatory multi url picker

* Split out tests for content with a multi URL picker.

* Refactor and added tests for publish a block with empty mandatory multi url picker

* Make tests run in the pipeline

* Fixed comments
2026-03-25 10:51:32 +07:00
Nhu DinhandGitHub 88d8a5acb3 E2E: QA Added acceptance tests for moving media items (#22232)
* Added tests for moving media

* Renamed tests

* Make tests run in the pipeline

* Updated name

* Reverted npm command
2026-03-25 03:37:20 +00:00
Andy Butland 0210dd00a0 Fix after merge. 2026-03-24 17:37:17 +01:00
b57aacc176 Localization: Update "MFA" label to "2FA" in language files (#22236)
* Update MFA label to 2FA in English language file

* Changed MFA to 2FA in all other language files.

* Revert "Changed MFA to 2FA in all other language files."

This reverts commit 203294e287.

* Changed MFA to 2FA in all other language files.

---------

Co-authored-by: Marc Love <marc@madebycrunch.com>
2026-03-24 17:29:52 +01:00
Andy Butland 41f62ae03b Merge branch 'main' into v18/dev 2026-03-24 16:58:46 +01:00
Andy ButlandandGitHub 23123adeaa Member Authorization: Return correct status codes for unauthenticated members (fixes #21638) (#22220)
* Handle API and surface controllers with correct status code and behaviour when a member isn't logged in.

* Addressed code review feedback.

* Further code review feedback.
2026-03-24 15:46:52 +01:00
Mads RasmussenandGitHub 851d96c2b8 Members: Fix Create Members based on Member Types in folders (#22241)
* utilize the member type structure repo to get member create options

* align member collection create action with other content types

* remove hardcoded icon

* Update constants.ts
2026-03-24 13:33:38 +00:00
Mads RasmussenandGitHub 70be022109 Backoffice: Migrate Templating, Language, Member Group, and Document Blueprint create entity actions to use entityCreateOptionAction extensions (#22214)
* register as create options

* restore label

* Remove ellipsis from document blueprint label

* Add collection create actions for tree item children

* Show ellipsis for labels with additional options

* Enable additional options for create actions

* Refactor language and member group create actions into create option actions

* Update UiBaseLocators.ts

* Add additionalOptions to create manifests

* Add ellipsis to names in create content modals

* Update DataTypeUiHelper.ts

* Update DocumentTypeUiHelper.ts

* Update creation action locators and tests

* Update LanguageUiHelper.ts
2026-03-24 11:41:40 +01:00
Sven Geusens b19f8a2eb1 Add v18/dev to nightly build trigger 2026-03-24 11:11:51 +01:00
Andy Butland 124c01cd6e Merge branch 'release/17.3.0' 2026-03-24 10:40:48 +01:00
Lee KelleherandGitHub 282e3af6b8 Entity Data Picker: Adds start node support to tree data-sources (#22172)
* Adds optional `requestStartNode`

to Entity Data Picker tree source confguration

* Changes the example Document data-source

to use a Document Picker for the start node,
instead of the Content Picker source.
As that is targeted across Documents, Media or Members.

* Example Documents data-source: implemented "start node"

* Renamed `requestStartNode` to `requestTreeStartNode`

* Code tidy-up
2026-03-24 09:21:18 +01:00
Andy ButlandandGitHub fd81ade58b Migrations: Fix package migrations not running after fresh install with packages (closes #22202) (#22204)
* Run package migrations synchronously on runtime restart after a fresh install.

* Add unit tests verifying fix and existing functionality.
2026-03-24 08:28:11 +01:00
Andy ButlandandGitHub 27c926940f Migrations: Fix retrust constraints migration targeting non-Umbraco tables and transaction failure (closes #22227) (#22229)
* Retrust only umbraco tables and catch errors at SQL level.

* Code review feedback.
2026-03-24 06:39:48 +01:00
Andy ButlandandGitHub 186498ef39 Dynamic Root: Fix current origin resolution for new unsaved content (closes #22213) (#22216)
* Fix issue where dynamic node query based from current node does not resolve for new documents.

* Add tests verifying the fix. General cleanup of code warnings in dynamic node implementations and tests.

* Addressed failing integration test and code review feedback.
2026-03-24 12:55:17 +09:00
Andy ButlandandGitHub 2859cb808a Management API: Add endpoint to get all member types allowed at root (#22226)
* Add endpoint for retrieving all member types allowed at root.

* Addressed code review feedback.
2026-03-24 12:33:54 +09:00
Andy ButlandandGitHub 51b7fbf5ee Tree Picker: Fix root item not deselecting in single-selection picker (closes #22073) (#22099)
* Ensure single-select tree doesn't allow selection of root and item.

* Add tests verifying behaviour.
2026-03-23 13:59:22 +01:00
3119b3a8ef Blueprints: Allow saving document blueprints with partial variant names (closes #22190) (#22210)
* Allow saving document blueprints with partial variant names.

* Address code review feedback.

* Use shallow copies instead of in-place mutation when filtering unnamed variants before delegating to base class validation.

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-03-23 13:27:11 +01:00
Sven Geusens d428cf2d5b Add v18/dev to nightly build trigger 2026-03-23 12:00:30 +01:00
Kenn JacobsenandGitHub 1a86c9f45c Change the default webhook payload type to "minimal" (#22217)
* Change the default webhook payload type to "minimal"

* Include expected defaults in webhook telemetry + use core constants instead of local strings
2026-03-23 09:19:17 +01:00
dc8941fefe EFCore Scoping: Preserve connection string before disposing EFCoreScope database (closes #22211) (#22212)
* preserve connectionString befor disposing EfCoreDatabase during dispose of EfCoreScope. Fixed by Claude Sonnet 4.6

* Add details of integration tests to memory files.

* Ensure original connection string is captured and remove unnecessary guard.

* Add further test verifying the fixed behaviour.

* Test clean-up.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-23 07:09:59 +00:00
Andreas ZerbstandGitHub eb33dcebdf E2E: QA: add acceptance tests for compositions (#22180)
* Updated helpers

* Moved to specific test files

* Added tests with compositions

* Updated helper

* Run tests on pipeline

* Fixed

* Updated helpers

* Added tests for variants

* Added tests

* Updated smoke

* Fixed

* Cleaned up

* Moved to before each

* Reverted test command
2026-03-23 06:50:46 +00:00
Nicklas KramerandGitHub 112250da90 Distributed Background Jobs: Preventing Jobs From Running When Database Is Read-Only (#22208)
* Disabling distributed background jobs when database is readonly

* Adding changes in accordance to code review
2026-03-20 13:15:26 +01:00
597300863a E2E: QA Updated acceptance tests for duplication action due to UI changes (#22206)
* Added ui helper for copy button

* Updated tests since the duplicate button is replaced by the copy button

* Update tests/Umbraco.Tests.AcceptanceTest/lib/helpers/UiBaseLocators.ts

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>

---------

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-03-20 10:19:11 +00:00
Nhu DinhandGitHub 4c8cf2146c E2E: QA Added acceptance tests for public access (#22158)
* Added constant variables for public access notification message

* Added ui helper for public access

* Added api helper for setup and delete public access

* Added api helper for create default member group

* Updated tests to use createDefaultMemberGroup instead of the directly create api

* Added tests for setting public access on content

* Added api helper for verify public access

* Updated ui helper for verify public access

* Updated tests for public access

* Make tests run in the pipeline

* Fixed comment

* Reverted npm command
2026-03-20 07:44:37 +00:00
Andy ButlandandGitHub e28de80212 Integration Tests: Avoid hidden BootFailedException in CoreConfigurationHttpTests (#22188)
Avoid hidden BootFailedException in CoreConfigurationHttpTests.
2026-03-20 07:55:24 +01:00
Nhu DinhandGitHub 3611a28966 E2E: QA Added acceptance test for HMAC secret key health check (#22141)
* Added constant variable for healthCheckMessage

* Added appsetting file for imaging setting config tests

* Updates name

* Added project for imagingSettingConfig

* Added ui helper for verify health check of Imaging HMAC Secret Key

* Updated tests for HMAC secret key health check with default settings

* Added tests for HMAC secret key health check is not configured

* Makes test run in the pipeline

* Fixed comment

* Clean code

* Reverted npm command
2026-03-19 15:03:59 +00:00
Nhu DinhandGitHub 5968bae002 Build: Cherry pick #22164 for V18 (#22165)
Serialize E2E stages and stagger branch schedules to reduce agent usage
2026-03-19 21:20:06 +07:00
Nhu DinhandGitHub 21bde287bb Build: Serialize E2E stages and stagger branch schedules to reduce agent usage (#22164)
* Serialize E2E stages and stagger branch schedules to reduce agent usage

* Removed unused condition

* Added condition
2026-03-19 21:19:23 +07:00
d0072a572e EFCore Scoping: Clear stale connection on pooled DbContext before returning to pool (closes #22124) (#22132)
* Clear stale connection on pooled DbContext before returning to pool.

* style: apply linter comment punctuation fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Removed unnessary test.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 14:50:34 +01:00
Andy Butland 4822ddd889 Distributed Locking: Add ROWLOCK hint to prevent cross-row contention on umbracoLock table (closes #22113) (#22126)
Use row lock for lock table.
2026-03-19 13:08:04 +01:00
Matthew CareandAndy Butland 48222951f3 Application URLs: Prevent back office hosts being overwritten in a shared database setup (closes #16741) (#22160)
* Add to backoffice hosts

Add to backoffice hosts, rather than completely replacing the array

* Add unit tests verifying fix.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-19 12:50:18 +01:00
7014f9a125 Dependencies: Upgrade NUnit and related test dependencies to latest major versions (#22155)
* Update Nunit and AutoFixture.Nunit to new versions

* Adding NonParallelizable

* Add blame-hang timeout to integration tests to detect hanging tests

* remove NonParallelizable, update NUnit3TestAdapter, add Ingore to CoreConfigurationHttpTests

* Resolve CoreConfigurationHttpTests hang with NUnit 4.

  - Use Task.Run in CreateHost to escape NUnit 4's SynchronizationContext
    which deadlocks sync-over-async calls from async test methods.
  - Use await using for factory disposal to avoid same deadlock on shutdown
  - Remove WithWebHostBuilder which wraps the factory in a
    DelegatedWebApplicationFactory that bypasses the CreateHost override.
  - Add ContentRoot property to UmbracoWebApplicationFactory so content
    root can be set without WithWebHostBuilder.
  - Set ModelsBuilder mode to Nothing to prevent BootFailedException.
  - Add AddTestServices for infrastructure test doubles (MainDom, etc.).

* Revert changes to pipelines.

* Remove remaining CollectionAssert using legacy syntax.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-19 11:49:08 +00:00
Andy ButlandandGitHub a986268d28 Distributed Locking: Add ROWLOCK hint to prevent cross-row contention on umbracoLock table (closes #22113) (#22126)
Use row lock for lock table.
2026-03-19 12:26:27 +01:00
Andy ButlandandSven Geusens 51ae5b66d7 Migrations: Fix property detection for invariant content types with culture-varying compositions (closes #22159) (#22167)
* Extract shared culture-resolution logic from ConvertBlockEditorPropertiesBase, ConvertLocalLinks, FixConvertLocalLinks, and MigrateSingleBlockList into PropertyDataCultureResolver, fixing a bug where NULL languageId (legitimate invariant data) was incorrectly treated as a deleted language reference.

Add unit tests covering all resolution paths including the bug scenario.

* Remove obsoletion on helper.

* Address code review feedback.

* Handle SetValue variation mismatch for invariant data on culture-varying compositions

* Fixed build error in tests.

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2026-03-19 12:08:16 +01:00
Andy Butland 49b3c24c9f Bumped version to 17.3.0-rc2. 2026-03-19 12:07:26 +01:00
Mads RasmussenandGitHub d76493fa76 Backoffice: Add tree item children collection views for Partial Views, Stylesheets, Scripts, Templates, and Document Blueprints (#22146)
* init implementation

* Add template tree item-children collection and views

* add base class

* Use Settings section for document blueprint paths

* Inline customElement names and update typings

* Make table collection view buttons compact

* remove collection action again as they require create options to be registered first

* move file

* fix export

* fix const exports

* Extract template tree repository alias to constants
2026-03-19 09:18:41 +00:00
b7f8a62f0d Migrations: Fix property detection for invariant content types with culture-varying compositions (closes #22159) (#22167)
* Extract shared culture-resolution logic from ConvertBlockEditorPropertiesBase, ConvertLocalLinks, FixConvertLocalLinks, and MigrateSingleBlockList into PropertyDataCultureResolver, fixing a bug where NULL languageId (legitimate invariant data) was incorrectly treated as a deleted language reference.

Add unit tests covering all resolution paths including the bug scenario.

* Remove obsoletion on helper.

* Address code review feedback.

* Handle SetValue variation mismatch for invariant data on culture-varying compositions

* Fixed build error in tests.

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2026-03-19 10:11:51 +01:00
Andy Butland 21c988309a Merge branch 'release/17.3.0' 2026-03-19 06:48:12 +01:00
f27e5a1917 Application URLs: Prevent back office hosts being overwritten in a shared database setup (closes #16741) (#22160)
* Add to backoffice hosts

Add to backoffice hosts, rather than completely replacing the array

* Add unit tests verifying fix.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-19 06:37:29 +01:00
Johannes LantzandGitHub 0e6ce7d691 Localization: Added missing for elements (#22079)
* umb-clipboard-entry-picker-modal: added missing localizations

* umb-trash-with-relation-confirm-modal: added missing localizations

* umb-bulk-delete-with-relation-confirm-modal: added missing localizations

* umb-bulk-trash-with-relation-confirm-modal: added missing localizations

* umb-duplicate-to-modal: added missing localizations

* umb-document-duplicate-to-modal: added missing localizations

* umb-sort-children-of-modal: added missing localizations

* umb-content-type-design-editor: added missing localizations

* umb-entity-user-permission-settings-modal: added missing localizations

* umb-clipboard-entry-picker-modal: Removed haredcoded close

* umb-clipboard-entry-picker-modal: Adjusted headline localize

* umb-entity-user-permission-settings-modal: Changed to correct headline key
2026-03-18 09:48:22 +00:00
Nicklas KramerandGitHub 67008d349c Last Synced: Adding A File System Approach to Subscriber Servers (#22145)
* Adding a file system approach to subscriber servers

* Adding tests

* Alternative lazy injection

* Adding delegate unit tests and making classes internal sealed.

* Adding a check to see if database is readonly

* Modifying DatabaseReadOnlyAccessor.cs
2026-03-18 10:34:36 +01:00
Niels LyngsøandGitHub 7536d6b95f Library: remove library sidebar app (#22139)
remove library sidebar app
2026-03-17 15:09:06 +00:00
634b1eed88 Media Picker: Add Cards/Table view switcher (closes #22005) (#22138)
* Add table view to media picker modal

* Use unique id in media picker selection handlers

* Add dateTime formatter and use in media picker

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Add dateTime localization tests

* localize view labels

* Persist media picker view in interaction memory

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-17 15:38:12 +01:00
3ece7b1276 Upload Field: Fix image overflowing content container (closes #22106) (#22107)
* fix(media): prevent upload field image from overflowing content container

The image element used `height: 100%` which resolved to a definite value
when rendered in the old flex-row layout (parent's stretch gave it a height).
After #21887 restructured the wrapper to flex-column, the parent no longer
provides a definite height, so `height: 100%` falls back to `height: auto`
and the image renders at its natural (potentially huge) dimensions.

Fix by giving `img` direct constraints (`max-width: 100%`, `max-height: 400px`,
`height: auto`) so it constrains itself regardless of the parent layout context.

Closes #22106

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* style(media): remove redundant max-height from :host, keep on img

The max-height: 400px is now on the img directly, so the :host constraint
is redundant.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(media): apply same image overflow fix to SVG upload preview

Same root cause as #22106: img relied on height: 100% resolving via
parent flex-stretch, which breaks in the flex-column layout from #21887.
Move constraints to img directly (max-width: 100%, max-height: 400px,
height: auto) and remove redundant/ineffective host properties.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* style(media): move min-height from :host to img in image and SVG previews

With height: auto on img, min-height on :host left an empty gap when the
image was shorter than the minimum. Moving min-height to img ensures the
checkerboard background fills the full minimum preview area consistently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(media): prevent image cropper focus setter from blinking on upload

The #image element had no CSS size constraints, causing it to render at
its natural dimensions briefly before the onload handler applied
width/height: 100% via inline styles. Adding max-width/max-height: 100%
ensures the image is already constrained on first paint, eliminating the
reflow blink when uploading a new image.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(media): use File object name for extension in file upload preview

When a file is dragged in before saving, the path is a blob URL
(blob:http://...) which produces a garbage extension when split on '.'.
The File object is already passed as a prop via the interface but was
unused. Prefer file.name for extension extraction when available.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-03-17 12:46:23 +00:00
Kenn JacobsenandGitHub 6036b13e94 Elements: Clean up container relations before deleting them (#22154)
Clean up element container relations before deleting them
2026-03-17 10:31:38 +01:00
cfa74db61a Routing: Resolve URL segment collision for siblings differing only in punctuation (closes #22070) (#22090)
* Routing: Resolve URL segment collision for siblings differing only in punctuation (closes #22070)

When sibling documents have names that differ only in punctuation
(e.g. "Title" vs "Title."), the URL segment provider strips punctuation
and produces identical segments, causing routing conflicts.

Add collision detection in DocumentUrlService.CreateOrUpdateUrlSegmentsAsync
that checks sibling segments (from both the in-memory cache and the current
batch) and appends a numeric suffix (-2, -3, etc.) when a collision is found.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Routing: Move URL segment collision detection to DocumentRepository name uniqueness (closes #22070)

Reverts the DocumentUrlService approach (URL-level `-2` suffixes) in favour of
detecting collisions at the document name level. When two sibling names produce
the same URL segment (e.g. "Title" and "Title." both clean to "title"), the
existing `(1)` naming convention is applied to the name itself, which then
yields a distinct URL segment.

Changes:
- Revert DocumentUrlService collision resolution logic
- Override EnsureUniqueNodeName in DocumentRepository to augment sibling names
  with phantom entries for URL segment collisions (via IShortStringHelper)
- Apply same augmentation in EnsureVariantNamesAreUnique for variant content
- Add IShortStringHelper constructor dependency (with obsolete compat pattern)
- Add unit tests verifying the phantom entry approach

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Routing: Refactor URL segment collision to direct segment comparison

Replace the indirect "phantom entries" approach with a clearer two-step
strategy as suggested in review:

1. Call base.EnsureUniqueNodeName() to handle literal name duplicates
2. Fetch siblings, compute URL segments, and increment (N) suffix until
   the resulting segment is unique

This is easier to reason about and avoids manipulating the SimilarNodeName
algorithm. The trade-off is a second sibling fetch (same indexed query),
which only runs on save.

- Replace AugmentNamesForUrlSegmentCollisions with EnsureUniqueUrlSegment
- Apply same pattern in EnsureVariantNamesAreUnique
- Remove phantom entry unit tests from SimilarNodeNameTests
- Add integration tests on ContentService for both invariant and
  culture-varying content with punctuation-only name differences

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Updated usages of obsolete constructors.

* Avoid second look-up of siblings data.

* Make EnsureUniqueUrlSegment unit testable, and add tests.

* Pass content.Id rather than 0 in variant unique name check.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-17 09:17:43 +01:00
d2e7fc1863 Dependencies: Update selected dependencies to latest major versions (#22060)
* update outdated dependencies to their latest major versions

* change version of JsonPatch.Net back to 3.*.*

* Upgrade Umbraco.Code package

* Update tests

* Resolve NUnit 4 migration issues causing test hangs

* Fix for dotnet test on the pipeline.

* Debug: Fix attempt for integration tests on the pipeline.

* Revert pipeline changes and go back to 5.2.0.

* Debug: Omit suspect tests.

* Debug: Disable tests with timeout.

* Debug: Try 4.6.0.

* Debug: Added reference to Microsoft.CodeAnalysis.CSharp.Workspaces.

* Roll back NUnit upgrade.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-17 06:37:21 +01:00
Henrik GedionsenandJason Elkin 7945bd408c Use Array.ConvertAll instead of LINQ .Select .ToArray 2026-03-16 21:21:10 +00:00
27b7f220a3 Elements: Fixes HasChildren for Element Folder entities (#22142)
* Fixes `HasChildren` for Element Folder entities

* Remove HasChilden mapping

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-03-16 17:01:08 +00:00
Andy Butland af9577e792 Redirect Tracking: Fix segment change detection and optimise descendant traversal (#22091)
* Optimise redirect tracker by avoiding re-producing of descendant nodes and avoiding descendant traversal when there has been no change to the node's URL segment.

* Delete inadvertently added file

* Allow URL segment providers to ensure descendent traversal if needed.

* Pushed missing files.

* Refactors to reduce large method code smells.
2026-03-16 09:21:17 +01:00
Andreas ZerbstandGitHub 9e360e8dc0 QA: Fix element tree integration tests and SQL Server container service error (#22130)
* fix SQL Server OFFSET/FETCH error

* added ActionElementBrowse.ActionLetter permission
2026-03-16 13:11:23 +07:00
Andy ButlandandGitHub 7363183ef6 Redirect Tracking: Fix segment change detection and optimise descendant traversal (#22091)
* Optimise redirect tracker by avoiding re-producing of descendant nodes and avoiding descendant traversal when there has been no change to the node's URL segment.

* Delete inadvertently added file

* Allow URL segment providers to ensure descendent traversal if needed.

* Pushed missing files.

* Refactors to reduce large method code smells.
2026-03-15 16:24:37 +01:00
marcloveUSNandGitHub 7f9570c671 Block Editors: Resolves incorrect "Discard unsaved changes" message when editing blocks with live editing (#22134)
Change setOneContent to setOneSettings for initialSettings

Line 661 calls setOneContent() with settings data instead of setOneSettings(). This pushes the settings element into the contentData array.
2026-03-13 20:21:46 +01:00
a2acb7a53f Code Clean-up (18): Remove obsoleted code flagged for removal and address TODO comments (#21980)
* remove obsolete constructor

* adjust RootDictionaryTreeController constructor to use non-obsolete constructor and remove obsolete base

* todo action v18

* remove ActivatorUtilitiesConstructor atribute that there's only one constructor

* remove obsolete class and method

* remove obsolete code in v18

* remove obsolete code from repositories

* remove obsolete for blocks

* remove obsolete code from services

* remove Icomponent

* remove incorrect IRequestSegmmentService

* remove obsolete properties

* undo change of blocklayoutitembase because of test failed

* bring back somes code due to pr 21999

* bring back some codes and update ContentRouteBuildertests

* remove obsolete code from domains, notification controller and some services

* remove obsolete constructor from ElementMapDefinition

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-13 14:40:13 +01:00
f56bad8989 E2E: QA: Added document segemented variant acceptance tests (#21957)
* Updated naming

* Updated path to test files

* created tests

* Reverted retries change

* Updated imports

* Added step

* updates based on comments and clean up

* Added vars

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-13 11:03:42 +00:00
Nhu DinhandGitHub d9db6b02ce E2E: QA Added .skip tags to failing acceptance tests due to known issues (#22122)
* Added .skip tags for the failing tests due to an actual issue

* Change the way to verify the validation message

* Added .skip tags for failing tests due to the actual issues
2026-03-13 16:30:00 +07:00
Nhu DinhandGitHub 8ae64d26fd E2E: QA Updated acceptance tests for bulk trash content due to UI changes (#22118)
* Added verfication step to avoid flaky

* Updated tests due to UI changes

* Format code

* Added waits
2026-03-13 16:27:42 +07:00
Nhu DinhandGitHub ae80d921c0 E2E: QA Updated acceptance tests in v18 due to the auth changes (#22110)
Updated tests due to the auth changes
2026-03-13 03:18:13 +00:00
Andy Butland 14a2ca89ea Adds XML documentation to elements management API controllers, models and mappers. 2026-03-12 18:20:13 +01:00
Andy Butland b2517e3302 Fix post merge issues. 2026-03-12 18:05:48 +01:00
Andy Butland f83949c508 Merge branch 'main' into v18/dev 2026-03-12 17:59:17 +01:00
862e8a6e0a Code Documentation: Add missing XML header documentation to the Umbraco.Cms.Api.Management project (#21785)
* Adding code comments to Umbraco.Cms.Api.Management

* Update src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/UpdateMemberGroupController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentBlueprint/MoveDocumentBlueprintController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/CopyDataTypeController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentType/CopyDocumentTypeController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/IsUsedDataTypeController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixing a missing closing brace on return docs.

* Fixing issue raised by copilot.

Issue was:

Inconsistent use of T: prefix in cref attribute. Other parameters in this PR use the interface name directly without the T: prefix (e.g., <see cref=\"IContentTypeService\"/>). Remove the T: prefix for consistency.

* Fix broken <returns> tags.

* Fixed incorrect descriptions.

* Added missing description.

* Fix positioning of comments.

* Fixed indentation.

* Use standard text for view model properties.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Emma L Garland <1649855+emmagarland@users.noreply.github.com>
2026-03-12 17:38:34 +01:00
Andy ButlandandGitHub 155c0c1d64 Sections: Sort sections by display name in user group assignment (closes #22094) (#22112)
* Order user group selected sections and sections for selection by name.

* Sort by weight rather than alphabetically.

* Feedback from code review.
2026-03-12 16:34:33 +01:00
Andy Butland af439c6a66 Fixes and additional documentation after merge. 2026-03-12 16:16:11 +01:00
Andy Butland 71d700ea28 Merge branch 'main' into v18/dev 2026-03-12 16:15:40 +01:00
104d5986a1 Code Documentation: Add missing XML header documentation to the Umbraco.Cms.Infrastructure project (#21782)
* Adding lots of missing documentation

* Update src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Infrastructure/Extensions/ScopeExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixing small issues and adding some more missing docs.

* Fixed indentation, blank lines and moved inline header comments into remarks.

* Fixed messages in UserRepository.

* Fixed indents in file scope namespaced files.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-12 15:15:16 +01:00
Niels Lyngsø 90b2062d85 Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Cms.Api.Management/Controllers/Content/ContentControllerBase.cs
#	src/Umbraco.Web.UI.Client/package.json
#	src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/ContentUiHelper.ts
#	tests/Umbraco.Tests.Integration/CompatibilitySuppressions.xml
#	version.json
2026-03-12 14:21:54 +01:00
Niels Lyngsø 35c6b46fdd update comments 2026-03-12 14:17:42 +01:00
502cab9ff2 Temporary File: Lowercase file extension before validation (closes #22096) (#22108)
* fix(core): lowercase file extension before validating against allowed/disallowed lists

Fixes case-sensitive comparison in UmbTemporaryFileManager where uploading a
file with an uppercase extension (e.g. .PDF) would be incorrectly rejected
even when the lowercase extension (pdf) was in AllowedUploadedFileExtensions.

Closes #22096

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(media): lowercase SVG extension check in media links info app

Fixes case-sensitive .svg check so that media files with uppercase
extensions (e.g. .SVG) correctly use the SVG viewer link.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(core): also lowercase config extension lists before comparison

The server may return extensions in any case (config is stored as-is).
Lowercase both sides to ensure the comparison is truly case-insensitive.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Ensure server-side checks for file extensions are case insensitive.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-12 10:30:07 +00:00
6444a2d2d7 E2E: Updated the acceptance tests to match the recent changes (#22088)
* Updated multiURLPickerSettings as there is a new setting for Culture-specific document links

* Updated tests for verify the default configuration of multi url picker data type

* Increased time for waiting the loader icon disappears to avoid the flaky tests

* Updated tests for reset manual URL using remove button due to locator changes

* Added ui helper for card collection view in content

* Updated tests to reflect that grid view is now the default instead of list view.

* Updated ui helper for public access saving button due to UI changes

* Removed unused code

* Fixed comments

* Removed unused test folder

* Updated auth to clear storage

---------

Co-authored-by: Andreas Zerbst <andr317c@live.dk>
2026-03-12 09:44:15 +00:00
6447e63170 Add JsonSchema support to the Management API for datatypes and contenttypes (#21771)
* Basic implementaion

* Tests and schema validation

* Attemp refactor

* Fix json single parent bug

* Surface doctype schema validation to management api

* Improve block schema and make validation errors less verbose

* fix validation error cleanup

* Improved GUID handling | added schema for all propertyEditors

* Add ContentTypeInputSchema

* move contenttype schemas to be actual jsonschemas

* Fix block limit on blocklist and grid

* add datatype schema batch

* Refactoring blocks json schema generation and add to richtext

* Package version update and more tests!

* ConvertToJsonNode optimization

* async refactor

* Add editorUiAlias to x-umbraco-properties and make DataType ref route dynamic

* Removed JsonSchema.net due to possible license issues

* Use void editor in the noop schema test

* Cleanup leftovers from Schema validation removal

* Move batch logic into batchcontroller

* Update src/Umbraco.Infrastructure/PropertyEditors/BlockJsonSchemaHelper.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Services/ContentTypeJsonSchemaService.cs

Improve lookup on building propertymetadata

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Fixed build error.

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-12 09:32:38 +01:00
37994a87db Management API: Return descriptive 400 for property variance mismatch (closes #22076) (#22100)
* Provide more descriptive management API responses for invariant with variant composition.

* Improved messaging and fixed integration tests.

* Fixed ordering of new ContentEditingOperationStatus values so existing values retain their integer equivalent.

* Suppress breaking changes in integration tests.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-03-12 08:57:53 +01:00
5aa3ccd88c E2E: QA Added acceptance tests for DisableDeleteWhenReferenced setting (#22017)
* Changed appsetting.json

* Added tests for disableDeleteWhenReferenced setting

* Added constant variable for descendingReferenceHeadline

* Moved doesModalHaveText to uiBaseLocator

* Updated warning message for bulk trash due to the recent changes

* Updated warningMessageForBulk

* Fixed comments

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-12 14:46:03 +07:00
Andy Butland 9271da4a73 Fixed mocks in media-type.db.ts. 2026-03-11 21:50:49 +01:00
Andy Butland 36e672ce8d Fixed mocks in media-type.db.ts. 2026-03-11 21:49:06 +01:00
Andy Butland b14dfcf92c Bumped version to 17.4.0-rc. 2026-03-11 20:56:43 +01:00
Andy ButlandandGitHub 43167710fa Content Picker: Fix item reference link navigation (closes #22085) (#22103)
Remove culture from document item ref href to fix content picker navigation.
2026-03-11 18:29:02 +00:00
be25c4b0a0 Referenced Items: Prevent move to recycle bin when referenced and DisableDeleteWhenReferenced is enabled (closes #21986) (#21999)
* Prevent move to recycle bin for documents and media when disable delete when referenced is configured.

* Addressed code review feedback and fixed failing client-side test.

* Add suppression for renamed integration test.

* Simplified solution by moving disableDeleteWhenReferenced setting to modal.

* Fix flicker.

* Apply disable on delete handling to bulk trash dialog.

* Add additional translations.

* Move disableDeleteWhenReferenced resolution to document and media action classes, so the value is passed as modal data rather than being resolved in the modal itself.

* Update OpenApi.json.

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-11 16:57:48 +01:00
b634e6a2d1 Media: Allow File media type as fallback when no specific extension match is available (closes #21733) (#22054)
* Allow "File" media type as fallback when no specific extension match is available at the upload location

* Added regression test.

* Addressed test feedback.

* Fix after merge.

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-11 16:53:26 +01:00
Jacob Overgaard e6a91e5f6c Merge remote-tracking branch 'origin/main' into v18/dev 2026-03-11 15:30:02 +01:00
651cb0a419 Auth: Fix re-entrant /token call after OAuth code exchange (#22097)
Move #inSessionUpdateCallback guard into #setSessionLocally() so all
callers are protected, not just makeRefreshTokenRequest()'s lock callback.

Previously, completeAuthorizationRequest() called #setSessionLocally()
directly without setting the flag. With keepUserLoggedIn=true and a short
TimeOut, session$ observers fired synchronously inside #setSessionLocally,
triggering #onSessionExpiring → validateToken() → makeRefreshTokenRequest()
before #inSessionUpdateCallback was ever set — causing a second /token call
immediately after the initial code exchange 200.

The no-Web-Locks fallback path in makeRefreshTokenRequest() had the same
gap. Moving the flag into #setSessionLocally() covers all call sites.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 15:10:29 +01:00
Andy ButlandandGitHub 89de02dd5d Relations: Fix relation type detail navigation from collection list (closes #22092) (#22095)
* Fix display of relation type detail view.

* Add export to index file.
2026-03-11 14:48:41 +01:00
Andy ButlandandGitHub 694364960e Fix the CSP in our local project to support iframing the marketplace (#22093)
* Fix the CSP in our local project to support iframing the marketplace.

* Update to use constant and HTTP scheme.

* Use constant for news dashboard to
2026-03-11 14:24:43 +01:00
14a047b090 Auth: Skip /token refresh when access token is still valid (#22087)
* Auth: Skip /token refresh when access token is still valid

Guard the per-request validateToken() call sites with #isAccessTokenValid()
in configureClient() and getLatestToken(). Previously, every API request
triggered a /token call even when the access token had not expired, causing
unnecessary token churn and OpenIddict ID2019 errors for in-flight requests.

Proactive refresh via UmbAuthSessionTimeoutController and startup validation
in app-auth.controller.ts are unaffected — those call validateToken() directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Auth: Remove redundant first-check validateToken() on app startup

setInitialState() already handles server verification before the router
evaluates guards — either via a direct /token call (makeRefreshTokenRequest)
or via peer session adoption (BroadcastChannel). The #isFirstCheck guard in
UmbAppAuthController was a leftover from the AppAuth/localStorage era, where
token state was restored from storage and needed a server round-trip to confirm
validity. That assumption no longer holds: if getIsAuthorized() is true after
setInitialState(), the session came directly from the server or from a peer
whose timing is still valid. Stale/revoked peer sessions are handled lazily
by the 401 interceptor, which triggers re-auth as needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Auth: Wait for ongoing cross-tab refresh before sending requests

Restores the cross-tab lock serialization that was implicitly provided by
the old unconditional validateToken() call. When another tab holds the
umb:token-refresh lock (keepUserLoggedIn proactive refresh), API requests
in this tab now wait for it to complete before proceeding. This prevents
sending requests with an access token that is about to be revoked, which
caused OpenIddict ID2019 errors on in-flight requests.

The fast path (token valid, no refresh in progress) remains: navigator.locks.query()
is a cheap browser-internal call, and the lock.request() no-op is only
incurred when a cross-tab refresh is actually happening.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Auth: Extract #ensureTokenReady(), improve naming and JSDoc

- Extract duplicate guard logic from configureClient() and getLatestToken()
  into a single #ensureTokenReady() private method
- Rename from #ensureValidToken() → #ensureTokenReady() to distinguish from
  the validate/valid naming cluster (validateToken, isAccessTokenValid)
- Add JSDoc to #isAccessTokenValid() clarifying it is a local timestamp check
  with no network call
- Improve JSDoc on validateToken() to make clear it forces a network refresh
  (unconditional /token call), distinct from the per-request #ensureTokenReady()
  gate which skips the call when the access token is still live

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(auth): prevent re-entrant /token call when session$ fires synchronously inside lock

With keepUserLoggedIn=true and a short access token lifetime (e.g. expiresIn ≤ buffer),
#updateSession() triggers session$ synchronously inside the lock callback. The observer
fires #scheduleCheck → #onSessionExpiring → validateToken() before the lock is released.
This re-entrant call captures sessionBefore = newSession (already updated), so the
reference guard cannot detect it, resulting in a duplicate /token request.

Fix by tracking #inSessionUpdateCallback around the #updateSession() call. Re-entrant
callers return true immediately; concurrent non-re-entrant callers are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 11:23:39 +00:00
6d9fdec8b1 Auth: Fix preview window stuck loading after Save and Preview (closes #22083) (#22089)
The window.opener guard in #setAuthStatus() was too broad — it skipped
setInitialState() for ANY window opened via window.open(), including the
preview window. This left isAuthorized stuck at false in the preview window,
causing the loading spinner to never resolve.

The guard is only needed for the OAuth code exchange popup (oauth_complete),
where calling setInitialState() could silently refresh the session, set
isAuthorized=true, and cause the popup to redirect to the backoffice instead
of completing the code exchange.

Fix: narrow the guard to window.opener + pathname === '/oauth_complete'.
The preview window (at path /preview) now correctly calls setInitialState(),
which restores the session from a peer tab via BroadcastChannel.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 10:13:56 +00:00
93b8560035 External Login Providers: Set SignOutRedirectUrl on backoffice sign-out to support external OIDC provider logout (closes #21854) (#21952)
* Fix issue signout oidc external login provider

* Update src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-11 09:13:39 +00:00
Jacob OvergaardandClaude Sonnet 4.6 0263245b36 Docs: Add backoffice CLAUDE.md reference and frontend auth pitfalls to root CLAUDE.md
- Add src/Umbraco.Web.UI.Client/CLAUDE.md to Project-Specific Documentation
  (was notably absent alongside Core and Api.Common)
- Expand Authentication section with frontend pitfalls: validateToken() per-request
  danger, window.opener scope issue, BroadcastChannel sender exclusion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 09:30:29 +01:00
Jacob OvergaardandClaude Sonnet 4.6 4bc2cb4bdc Docs: Document auth architecture and cross-tab coordination edge cases
security.md:
- Expand auth section with v17 httpOnly cookie model, [redacted] pattern,
  configureClient() usage, and explicit warning against calling validateToken()
  per request (causes token churn and ID2019 errors)

edge-cases.md:
- window.opener is set for any window.open() target, not just OAuth popups —
  must check pathname too (root cause of #22083 preview regression)
- BroadcastChannel does not deliver to the sender — use local-only setters
  inside handlers to avoid N² broadcast storms
- sessionRequest must guard with isSessionValid() before responding
- Web Lock umb:token-refresh pattern for cross-tab refresh deduplication

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 09:27:43 +01:00
a113ceae41 Backoffice: Update vite from 7.1.11 to 7.3.1 (#22065)
* Backoffice: Update vite, vite-plugin-static-copy, vite-tsconfig-paths

- vite: ^7.1.11 → ^7.3.1
- vite-plugin-static-copy: ^3.1.3 → ^3.2.0
- vite-tsconfig-paths: ^5.1.4 → ^6.1.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* build(deps): bumps vite in umbracoextension template

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-11 09:13:19 +01:00
Andy ButlandandGitHub 959f7d57d2 Public Access: Align state and initial display of toggles and buttons on modal (#22086)
Align state and initial display of toggles and buttons on public access modal.
2026-03-11 08:55:53 +01:00
38f68f007e E2E: QA Updated the UI helper to verify that the image cropper is rendered (#22046)
* Updated ui helper to verify the image cropper is rendered

* Added .skip for the failing tests due to the actual issue

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-11 03:47:17 +00:00
fb5cad6e86 E2E: QA: Updated locator to find rollback button on the document workspace (#22030)
Updated locator to find rollback button on the document workspace

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-11 10:12:21 +07:00
6acb0ba002 Management API: Add batch read endpoints for Document Types, Media Types, Member Types, and Data Types (#21565)
* Add bulk fetch endpoints for retrieving full details for multiple entities by provided IDs, for data, document, media and member types.

* Switch to GET endpoints.

* generate new managment api types + sdk

* Update to use "batch" over "fetch".

* Update OpenApi.json and client-side types/sdk.

* Add endpoint summaries and descriptions.

* Align controller method signatures with use of HashSet<Guid> over Guid[].

* Backoffice Performance: Client-side bulk fetch of Element Types for Blocks, Content Type Compositions, and Data Types to reduce API requests (#21610)

* Add readMany for document type details

* Add batch read methods to detail interfaces

* Pre-register content-type structures and bulk load

* Add readMany support to detail request managers

* Simplify loadType and delegate to setType

* add js docs to detail data request manager

* add unit tests for detail data request manager

* Add byUniques support to detail store/repository

* implement readMany for data types

* fix typescript errors

* Preload and pass data type details to properties

* Update content-type-structure-manager.class.ts

* Replace per-property UmbDataTypeDetailRepository requests with the structure manager's bulk-loaded data type details

* Deduplicate inflight detail read/readMany requests

* Use 'read:' inflight cache key prefix

* Add bulk detail requests & status helpers

* Add management API request/cache for media/member types + requestByUniques support

* use observe controller instead of rxjs

* adjust to new apis

* rename prop to make it easier to read

* throw on error

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>

* remove unused import

* Fixes to failing E2E tests.

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Mole <nikolajlauridsen@protonmail.ch>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-10 22:04:43 +01:00
d8e1318290 Notifications: Correct the deep link URL in notification emails (closes #22047) (#22050)
* Fixed link in notification to editable document.

* Update translations using legacy mail format.

* Delete inadvertently added file

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-10 22:03:02 +01:00
23bc9ed702 Public Access: Preserve ancestor settings in dialog when setting up protection (closes #21740) (#21742)
* Allowed for easier public access management.

* Revert the update controller as that is being handled by the frontend.

* Cleaning up pull request

* Preserving obsolete function, updating controller to pass optional parameter.

* pass in the includeAncestors parameter

* Added in an alert message for when the permissions are being inhereited.

* Complete resolution of breaking changes on IPublicAccessPresentationFactory.

* Update call to controller from integration tests.

* Fixed variable name typo and whitespace.

* Added clarifying comment to client-side behaviour.

* Supressed the breaking change on the controller with the additional parameter.

* Added unit tests for PublicAccessPresentationFactory.

* Added localisation for ancestor label.

* Typo and whitespace.

* Updating the model to allow for switching between methods while still preserving ancestor selections.

* update locatlizations

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-03-10 19:32:58 +00:00
fbb5d871be Link Picker, RTE: Support linking to a specific culture (#21466)
* add language selection for link picker

* update model for link and rte when have culture

* resolve illegal imports

* update ApiLink

* Update ApiLink create content

* Update LocalLinkTag

* remove culture from picker modal

* remove culture from picker input

* update unit test, process culture from modalValue

* Use compile time regular expressions.

* wip custom document picker for multi url picker

* Set document link picker modal size to small

* render variant aware picked document item

* utiliza variant context in link picker modal

* Update link-picker-modal.element.ts

* remove unused

* remove unused

* remove unused

* remove unused

* Update types.ts

* Update tree-picker-modal.element.ts

* Update document-picker-modal.token.ts

* Update document-item-ref.element.ts

* Update document-item-data-resolver.ts

* Update document-item-data-resolver.ts

* Update tree-picker-modal.element.ts

* Update tree-picker-modal.element.ts

* Update tree-picker-modal.element.ts

* remove unused

* fix lint errors

* Update document-link-picker-modal.element.ts

* Skip language selector when <=1 language

* Fix typo in variant context comment

* Use strict equality for document type check

* Localize document picker headline

* remove unused default language

* Don't fallback culture when updating link

* Update document-link-picker-modal.element.ts

* use uui-combobox for a11y benefits

* remove unused code

* Cache repositories and reuse data resolvers

* clean up

* Update input-multi-url.element.ts

* Add multi-url-picker constants exports

* Update index.ts

* Tidied up code comments and attributes following merge. Addressed code review comments.

* Initialize link picker in async firstUpdated

* Await pickerSelect in onPickerSelection

* Await variant context & picker select calls

* Await setCulture in language handler

* Include culture in document edit href

* Add data type config for culture specific document links

* Localize culture-specific document link UI

* change of wording for configuration

* use Auto (visitor's language) for default option

* localization updates

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-03-10 18:00:21 +00:00
Niels Lyngsø dd89a147d3 Merge branch 'v17/improvement/refactor-21186-with-one-js-cycle' 2026-03-10 17:36:12 +01:00
Andreas Zerbst 421d616682 Merge branch 'main' into v18/dev
# Conflicts:
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/ApiHelpers.ts
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/DataTypeUiHelper.ts
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/UiBaseLocators.ts
#	tests/Umbraco.Tests.AcceptanceTest/lib/helpers/UserApiHelper.ts
#	tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/MediaPicker.spec.ts
#	tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/User/ContentStartNodes.spec.ts
#	tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/User/MediaStartNodes.spec.ts
#	tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/UserGroups.spec.ts
2026-03-10 17:05:11 +01:00
Niels Lyngsø 564ec5b490 fix decorator test 2026-03-10 16:14:07 +01:00
Niels LyngsøandGitHub 4723713a31 Core: Minimize await to a single JS cycle (refactor #21186) (#22074)
* refactor to use Abort Controller instead of requestAnimationFrame

* dismantle currentScope immediately when disconnected

* improve life cycle
2026-03-10 15:08:42 +00:00
Niels LyngsøandGitHub d957c99442 Merge branch 'main' into v17/improvement/refactor-21186-with-one-js-cycle 2026-03-10 15:26:45 +01:00
Niels Lyngsø f2269aaa4c use undefined for no currentScope 2026-03-10 15:26:06 +01:00
Johannes LantzandGitHub 1e8ef4e644 Localization: Added missing Japanese translations (#22056)
* Added missing Japanese translations

* Formatted japanese localization file
2026-03-10 15:13:19 +01:00
Niels Lyngsø 6076a582ee extension-slot tests 2026-03-10 15:12:40 +01:00
Niels Lyngsø b09e7781ba apply extreme life cycle tests 2026-03-10 15:02:23 +01:00
Niels Lyngsø f976df164f use queueMicrotask 2026-03-10 14:54:25 +01:00
aa993af648 Auth: Fix popup flow showing backoffice after session timeout re-auth (#22071)
* Auth: Fix popup flow showing backoffice after session timeout re-auth

When a session times out client-side, the parent tab's #session was still
non-null (the timeout signal fires without clearing the session). When the
re-auth popup opened and called setInitialState(), it sent a sessionRequest
via BroadcastChannel. The parent responded with the expired session because
the handler only checked `if (session)` — not if the session was still valid.

The popup's auth context then thought it was already authorized, causing the
oauth_complete handler to hit the early-return `redirectToStoredPath` instead
of completing the authorization code exchange. The popup navigated to the
backoffice instead of exchanging the code and closing.

Fix: only share the session in response to sessionRequest if isSessionValid()
returns true (i.e. session.expiresAt > now).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Auth: Fix re-auth popup not opening on session timeout

Two issues:

1. When the countdown modal timer reached 0, it called onLogout() -> signOut()
   which performed a full page redirect to /logout before timeoutSignal could
   fire. The re-auth popup (makeAuthorizationRequest('timedOut') in
   UmbAppAuthController) was never triggered. Fix: reject the modal on timer
   expiry instead of calling onLogout(). The catch block in #openTimeoutModal
   then calls #tryValidateToken(); if the refresh token is still valid the
   session is silently renewed, otherwise timeOut() fires -> timeoutSignal ->
   re-auth popup opens.

2. Only the Web Lock leader tab was showing the timeout countdown modal.
   All tabs should show the warning so the user can respond from any active
   tab. Remove the lock-leader election logic — show the modal on every tab.
   When any tab successfully refreshes (Continue button or silent refresh), the
   session$ observer fires in all tabs, closing the modal everywhere.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Auth: Show re-auth popup when timeout countdown expires

When the countdown reaches zero the user was away and the session has
effectively expired — silently refreshing is the wrong behaviour. Instead:

- Add onExpired callback to UmbModalAuthTimeoutConfig, called (instead of
  onLogout) when the countdown hits 0.
- The controller sets onExpired -> timeOut(), which clears the session and
  fires timeoutSignal. UmbAppAuthController picks this up and calls
  makeAuthorizationRequest('timedOut'), opening the re-auth popup so the
  user can sign back in without losing their work.
- The modal uses submit() (not reject()) on expiry so the catch block's
  tryValidateToken() is not triggered.
- The Logout button still calls signOut() as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Auth: Close re-auth modal on other tabs when session is restored

When all tabs showed the re-auth modal and the user signed in on one tab,
the authorized BroadcastChannel message updated every other tab's auth
context but nothing triggered the modal to close on those tabs.

Fix: observe isAuthorized in UmbAppAuthModalElement. When it becomes true
(either from local sign-in or from another tab's BroadcastChannel message),
call #onSuccess() to submit and close the modal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: adds null guard

* docs: updates CLAUDE.md to let it know that there is a circular check call

* fix: fixes issue where the popup window could redirect to and show the full backoffice inside

* fix: ensures that the timeout modal is not shown until the buffer window is reached and extend the buffer window in case of short timeouts, and use the full expiresAt value for timeout but only the accessTokenExpiresAt for refresh of token

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 13:48:10 +00:00
Niels Lyngsø 5898a6b36b tests for disconnection life cycle 2026-03-10 14:36:10 +01:00
Niels LyngsøandGitHub 56f269e3ab Merge branch 'main' into v17/improvement/refactor-21186-with-one-js-cycle 2026-03-10 14:32:04 +01:00
Niels Lyngsø 2bd69fe329 improve life cycle 2026-03-10 14:30:03 +01:00
Andy ButlandandGitHub 3aa41920ce Dependencies: Update MailKit to 4.15.1 (#22028)
Update MailKit to 4.15.1.
2026-03-10 14:13:55 +01:00
e1ffb63aff Routing: Safely ensure AliasUrlProvider URLs have a leading slash (#22068)
* Append leading / to AliasUrlProvider URLs only if it doesn't already have one

* Add unit tests for AliasUrlProvider.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-10 12:09:39 +00:00
d6892ec06c Management API: Defensively handle path integrity issues when resolving ancestors (closes #21822) (#22036)
* Defensively handle node path integrity issues when resolving ancestors.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-10 13:06:16 +01:00
f324f4cd0d Member Service: Fix skip/take pagination in GetAll (closes #22006) (#22010)
* Fixed issue with GetAll on MemberService where skip/take weren't translated to pageIndex/pageSize.

* fix(core): fix paging in MemberService.GetAll skip/take overload

The skip/take overload was passing skip and take directly as pageIndex
and pageSize to the repository, causing incorrect pagination for any
non-zero skip value. Use PaginationHelper.ConvertSkipTakeToPaging to
correctly convert skip/take to page index/size, matching the pattern
used by all other services.

Also update ContentTypeIndexingNotificationHandler to call the
pageIndex/pageSize overload directly, avoiding the redundant conversion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Treat empty or whitespace filter as no filter in MemberService.GetAll

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 12:50:00 +01:00
Andy ButlandandGitHub 93a38eb707 Relations: Exclude relateParentDocumentOnDelete from EmptyRecycleBin reference check (closes #21926) (#21954)
Fixes ability to empty the recycle bin when DisableDeleteWhenReferenced is set to true.
2026-03-10 12:43:47 +01:00
b3f5ba3652 Auth: Addresses regression where you could not configure separate auth cookie names (closes #22049) (#22057)
* feat: adds new SiteName setting to cookie options to use as a postfix for oauth cookies

* fix: adds configured postfix to oauth cookies to make them work on multiple sites on same domain (fixes regression)

* fix: addresses an issue where the AuthCookieName option was not respected for the _EXPOSED auth cookie

* Update src/Umbraco.Core/Configuration/Models/BackOfficeTokenCookieSettings.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Moved the "exposed" cookie config to IConfigureNamedOptions

* Add missing constants

* Add unit tests to prove the site postfix

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-10 12:28:26 +01:00
5e31ac2410 Backoffice: Fix circular dependencies introduced by #21830 and #21846 (#22064)
* Backoffice: Fix circular dependencies introduced by PRs #21830 and #21846

Two circular dependency chains were created by the combination of recent
auth rewrites and the auth modal split:

1. `resources ↔ auth`: api-interceptor.controller imported UMB_AUTH_CONTEXT
   from auth, while auth.context imported UmbApiInterceptorController from
   resources.

2. `server → resources → auth → server`: umb-auth-view.element imported
   UMB_SERVER_CONTEXT from the server package, and was reachable from
   auth/index.ts via the components barrel added in #21846.

Fix for circular 1: Introduce UmbAuthSignalerContext in resources — a
lightweight bridge context with isAuthorized and requestTimeout(). The
interceptor creates it and owns it directly; auth context consumes it via
consumeContext to bridge its own authorization state and react to timeout
signals. Resources now has zero knowledge of the auth package.

Fix for circular 2: Remove umb-auth-view.element from auth/components/index.ts.
The modal already imports it directly within the package; app-auth.element
uses it as a custom element tag string with no class import needed.

Also updates MAX_CIRCULAR_DEPENDENCIES from 1 → 0 since both known cycles
are now resolved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Backoffice: Fix circular dependencies - part 2

- Remove auth dependency from server.context.ts: replace eager constructor
  side-effect (consumeContext + HTTP fetch) with lazy defer()-based observable
  using a backing field flag; fetch only happens on first subscription to
  isProductionMode
- Re-add umb-auth-view.element.ts to auth/components barrel (now safe since
  server no longer imports from auth)
- Ensure umb-auth-view is registered on the /logout route by adding a
  side-effect import in app-auth.element.ts
- Fix JSDoc in auth-signaler.context.ts and api-interceptor.controller.ts to
  correctly describe ownership and direction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 11:05:35 +00:00
d42e8114c5 Account login: Separate AllowConcurrentLogins settings for users and members (closes #21667) (#21940)
* Make cookie renewal conditional to fix AllowConcurrentLogins enforcement.

* Reduce SecurityStampValidatorOptions validation interval for users to zero.

* Apply member security stamp options.

* Addressed code review feedback.

* Add separate settings for AllowConcurrentLogins for members and users.

* Clarify comment.

* Further unit tests as suggested by code review.

---------

Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
2026-03-10 10:46:12 +00:00
dbc0b430ce Templates: Add direct Swashbuckle dependency to extension template (closes #21864) (#21869)
Ensure Swashbuckle version is aligned with Umbraco in the extension template.

Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
2026-03-10 10:28:34 +00:00
f3a369a5c0 Migrations: Run unattended upgrades in background, add liveness/readiness health probes (closes #21987) (#22020)
* Move unattended migrations to a background service, allowing liveness checks to recognise the application as healthy but not yet ready to serve requests.

* Add maintenance protection to surface controllers.

* Add protection for delivery API in upgrading state.

* Add protection for management API in upgrading state.

* Skip dynamic route transformer during Upgrading state (ensures surface controllers with attribute routing are handled in the upgrading state).

* Fix regression in attended upgrade state.

* Addressed code review feedback.

* Tidied up comments.

* Scope readiness health check predicate to Umbraco's own check.

* Fixed failing integration test.

* Removed TestCase from test with only a single case.

* Fix localization for "backoffice"

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>

* Removed UpgradeFailed from OpenApi.json and client-side types.

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-03-10 11:28:23 +01:00
Andy ButlandandGitHub ca2397a603 Account login: Enforce AllowConcurrentLogins for backoffice users and members (#21928)
* Make cookie renewal conditional to fix AllowConcurrentLogins enforcement.

* Reduce SecurityStampValidatorOptions validation interval for users to zero.

* Apply member security stamp options.

* Addressed code review feedback.
2026-03-10 11:05:51 +01:00
Niels Lyngsø 1478df4d4e dismantle currentScope immediately when disconnected 2026-03-10 10:46:17 +01:00
Niels Lyngsø ea5dbfa56f refactor to use Abort Controller instead of requestAnimationFrame 2026-03-10 10:11:01 +01:00
f2ecac6055 Dependencies: Updates @umbraco-ui/uui to 1.17.2 to fix multiple folder drag-and-drop failing (closes #21837) (#21886)
* fix(media): ensure sequential creation in media drag-and-drop

When multiple folders are dragged into the Media section, the creation
handlers (#handleFile/#handleFolder) were not awaited in the batch loop.
This caused child items to attempt server operations before their parent
folders were fully created, resulting in 404 errors for subsequent items.

Adding await ensures each item is fully created before the next is
processed, which is required because child items in the flat list
reference parent folder IDs that must exist on the server.

Closes #21837

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Task: Bump @umbraco-ui/uui to 1.17.2

Includes the fix for multi-folder drop DataTransfer staleness
(umbraco/Umbraco.UI#1339).

* qa(dropzone): add unit tests for UmbDropzoneManager folder flattening order

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:29:49 +01:00
Andy ButlandandGitHub 6cf80a0723 Migrations: Run AddSortableValueToPropertyData before MoveDocumentBlueprintsToFolders (#22063)
* Ensures all columns on property data exist before an earlier migration that requires them runs.

* Clarified comment.
2026-03-10 08:24:21 +00:00
Andy Butland 1dc35d59c1 Merge branch 'release/17.2.2' 2026-03-10 06:41:46 +01:00
11a412c0fd Merge commit from fork
* Add authorization checks for domain operations.

* Remove duplicate 403 ProducesResponseType attributes.

BackOfficeSecurityRequirementsOperationFilterBase already adds 403
responses for endpoints whose controllers inject IAuthorizationService.

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-03-10 05:11:16 +01:00
Andy ButlandandGitHub 2624b25e38 Merge commit from fork 2026-03-10 05:10:31 +01:00
Andy ButlandandGitHub 5f389f8bb4 Merge commit from fork
* Protect endpoint that sets user groups for a user collection to prevent elevation of permissions for users.

* Update tests from code review feedback.
2026-03-10 05:07:41 +01:00
3220526151 Entity Data Picker: Add configurable Picker Views for Collection Data Sources (#21738)
* Add alias property to collection config interface

Introduced an 'alias' property to the UmbCollectionItemPickerModalCollectionConfig interface

* render collection element when modal is configured with an alias

* expose a picker modal route

* use collection in use picker

* adjust spacing

* add config option for selectOnly

* dynamic modal alias

* support selectable entity item ref

* wip entity data picker collection + ref and card views

* Add entity collection item card extension type + default elements

* implement user collection item card

* fix selection events

* map to prop

* add prop/attr for href

* add support for which detail properties to show

* update type import

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/item/entity-collection-item-card/entity-collection-item-card.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* import card in correct file

* Fix event listener binding for selection events

* implement disabled property for collection item cards

* init commit of collection item ref extension

* fix imports

* add element interface

* Implement UmbEntityCollectionItemElement interface in item cards

Added the UmbEntityCollectionItemElement interface to document and user collection item card elements for improved type safety and consistency. Updated type exports to include the new interface.

* Update collection item ref to use uui-ref-node

Replaces the placeholder div with a uui-ref-node component, passing relevant item properties and event handlers. Adds dynamic icon rendering using umb-icon.

* Refactor entity collection item elements to use shared base

Introduces a new abstract base class for entity collection item elements, consolidating shared logic for card and ref variants. Updates card and ref element implementations to extend the new base, and refactors extension manifest interfaces for consistency. This improves maintainability and reduces code duplication.

* use class instead of magic string

* Use entity collection item card in picker view

Replaces the placeholder card markup with the <umb-entity-collection-item-card> component, enabling selection and deselection functionality for items in the entity data picker card collection view.

* Update entity item ref to collection item ref

Replaces <umb-entity-item-ref> with <umb-entity-collection-item-ref> in the picker collection view. Adjusts event handlers and select-only logic to improve selection behavior and component consistency.

* utilise ref and card kind for picker views

* introduce ref and card collection view kinds

* Utilise card kind for user collection view

* Add item-specific href support to collection views

Introduces a requestItemHref method to collection contexts for retrieving item-specific hrefs. Updates card, ref, and user table collection views to use these hrefs, enabling dynamic linking for collection items. Refactors user table name column layout to accept href via value prop instead of constructing it internally.

* Update ManifestCollectionView import path

Changed the import of ManifestCollectionView from '../extensions/types.js' to '../view/types.js' to reflect its new location.

* remove unused

* use size medium for entity collection item picker

* use box

* render entity actions

* use edit path builder for user links

* rename method

* Revert "rename method"

This reverts commit 4df577688e.

* Update collection-default.context.ts

* make type lint ignore unused args with an underscore

* temp remove unused

* only make collection vie selectable if there are any registered bulk actions

* don't render name link if there is no href

* fix imports

* Render selection actions only if bulk actions exist

* use selectable state

* Update language-table-collection-view.element.ts

* Update language-table-collection-view.element.ts

* Update card-collection-view.element.ts

* clean up

* Refactor collection views to use shared base class

* refactor(collection): parallelize href fetching and make method private

* docs(examples): update collection example to use card and ref kinds

* docs(examples): add icon property to collection example data model

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/view/types.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update collection-bulk-action.manager.test.ts

* Removed duplicate and redundant '@typescript-eslint/no-unused-vars' rule definitions, consolidating the configuration to use only 'argsIgnorePattern'.

* Handle missing user href in name column layout

Replaces the user name link with a span when the href property is not provided, preventing broken links in the user table name column layout.

* Update user-table-name-column-layout.element.ts

* pass modal data and value to routable modal

* Update picker-input.context.ts

* support selectableFilter

* scaffolding of a collection text filter extension

* Refactor collection text filter to use API interface

* Fix incorrect tag

* Update types.ts

* Update collection-text-filter.extension.ts

* Add cancelation to debounced search on destroy

* clean up

* add js docs

* two way binding of filter value

* clean up

* Add collection text filter manifest example

Introduced a new filter manifest for the example collection and updated the main manifests file to include it. This enables a text filter extension for the example collection.

* Delete unused element and context

* Update src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/user-group-collection.context-token.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update user-group-table-collection-view.element.ts

* support search for tree item and collection item pickers

* add spacing between collection ref items

* add margin between picker search result items

* remove spacing after last item

* remove padding in search results

* Update collection-item-picker-modal.element.ts

* move select only logic to collection selection manager

* add tests for collection selection manager

* change to filter label instead of search

* delete unused user grid collection view

* Select-only mode is now only disabled when all items are deselected, rather than on every deselection.

* prepare umb table for pickers

* utilize UmbCollectionViewElementBase in user table collection view

* remove console log

* handle select all and select item from same event

* bulk actions workaround

* add bulk action in collections feature toggle

* remove unused method

* make fields optional to avoid a breaking change

* remove unused import

* fix typescript errors

* adjust search styling

* hide with css

* fix ts errors

* Add modal data support to picker input context

Introduces methods to set and get modal data in UmbPickerInputContext, allowing base configuration for picker modals. Updates modal data handling to merge stored modal data with provided data for both direct picker opening and modal route setup.

* Fix bulk action manager test initialization

Added calls to setConfig in tests to properly initialize the observer before subscribing to hasBulkActions. Simplified the test logic for checking emissions when actions are present.

* Update tree-picker-modal.element.ts

* Update picker-search-result.element.ts

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/view/umb-collection-view-element-base.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Use ifDefined for modal route in user input button

* Use ifDefined for href binding in entity data picker

* Fix collection alias binding in item picker modal

* wire up user table collection view with selectableFilter

* clean up controller aliases

* Update collection-item-picker-modal.element.ts

* Update collection-item-picker-modal.element.ts

* Add support for collection items with thumbnails

Introduces thumbnail support for collection items by extending models and updating the default collection item card to render thumbnails when available. Adds a new example data source and manifest for items with thumbnails, and updates grid styling for card views.

* Improve card grid responsiveness and card sizing

Added a new CSS variable for large card min-width and updated the card grid to use container queries for responsive column sizing. Adjusted user card styles to ensure proper sizing and layout within the grid.

* add example image to thumbnail example

* introduce generic card component

* wip picker views configuration

* Update manifests.ts

* store value as alias

* Improve handling of missing collection view manifests

Refactors manifest storage to use a Map for faster lookup by alias and updates rendering logic to handle missing manifests gracefully. Now displays a 'not found' message with a remove button for missing collection view manifests.

* add sorting

* rename

* Add confirmation modal before removing picker view

* remove unused

* move collection selectOnly logic to context

* Update user-picker-modal.token.ts

* Add data-source package and integrate in input-entity-data

* Add optional description to collection items

* introduce extension picker data source

* fix problem with shallow copy because of js module in object

* nest manifest data

* Hide pagination when all items are shown

* Add a fallback page size

* merge extension insight code with extension code

* clean up

* Add optional description support to default item ref

* Revert "Add data-source package and integrate in input-entity-data"

This reverts commit e02881e8b6.

* fix post merge

* add input-extension utilizing input-entity-data

* proxy value and selection

* add todo

* temp hardcode config

* add typed config model

* Support multiple extension types in filters

* Use extensionTypes filter and deprecate type

Standardize extension collection filtering by introducing extensionTypes and phasing out the old type field.

* More explicit type name

* Expose allowedExtensionTypes as a @property on UmbInputExtensionElement

* Add text filter support for entity data picker

* remove reexport as this is not public available

* remove unused

* clean up

* clean up

* Add storage and getter for allowedExtensionTypes

* Inline collection view alias and remove constant

* Update vite.config.ts

* Update manifests.ts

* Update extension.picker-data-source.ts

* add tests for extension picker data source

* change to an observable feature config

* make feature object optional

* add unit tests

* Reference condition class directly in manifests

* Simplify collection view types and refactor setup

* remove todo

* implement input-extension on picker views configuration

* Add collection view aliases and defaults

* use correct type

* make name optional

* remove debugger

* delete - merge gone wrong. They are now called figure-cards

* map views to layouts

* Add viewsOverride to enforce collection layout order

* clean up observers if data source type changes

* remove unused

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-03-09 17:34:14 +00:00
Rick ButterfieldandGitHub e127bbc3ae Custom Views: Prevent re-rendering Block Views and Properties (#21186) 2026-03-09 17:03:15 +00:00
Andy ButlandandGitHub 301d3c98ba URL Picker: Fix title field only showing first character when typing URL (closes #22048) (#22053)
* Ensures title is set in full, and only updated when not already set, when entering a URL manually.

* Addressed code review feedback.
2026-03-09 16:55:59 +00:00
4ab34b1a2b Auth: Split auth modal into reusable view and introduce new non-dismissable modal type (closes #19628) (#21846)
* Auth: Split auth modal into reusable view and thin modal wrapper

Extract the full login screen UI from umb-app-auth-modal.element.ts into
a standalone umb-auth-view.element.ts that extends UmbLitElement. The
modal becomes a thin wrapper that delegates rendering to the view and
bridges onSuccess to _submitModal().

The view defaults userLoginState to 'loggedOut', so the /logout route
renders it directly as a component without needing to cast or configure
properties.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Fix imports and add readonly to styles in umb-auth-view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: import directly from main app itself to avoid dynamic imports

* Auth: Reopen timeout modal on dismiss and fix login layout height

Reopen the auth modal in a loop when the session has timed out, so
the user cannot dismiss it without re-authenticating. Fix login
layout height from calc(100vh - 64px) to 100vh with box-sizing.

Height fix credit: Lan Nguyen (PR #19843, closes #19628)

Co-Authored-By: Lan Nguyen <lan@umbraco.dk>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Fix timeout modal reopen by removing explicit modal key

The do/while loop to reopen the modal on dismiss was failing because
reusing the same key caused a race condition in the modal manager —
appendToFrozenArray replaced the old entry but the container's
_modalElementMap still held the stale key, preventing creation of
the new modal element. Letting each open() generate a unique key
via UmbId.new() avoids the collision entirely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Prevent auth modal from being dismissed via ESC

Add UmbPersistentModalDialogElement that extends UUIModalDialogElement
and intercepts ESC keydown to prevent the native dialog cancel behavior.
The auth modal now always uses this element via type: 'custom', ensuring
users must complete authentication rather than dismissing the modal.

Also simplifies #showLoginModal by using umbOpenModal() and removing
the do/while reopen loop which is no longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: renames file and adds appropriate exports

* Auth: Use AbortController for listener cleanup and add cancel handler

Use AbortController to manage event listeners, preventing accumulation
if _openModal is called multiple times. Add cancel event handler
alongside keydown as a fallback for the native dialog cancel behavior.
Clean up listeners on forceClose.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Lan Nguyen <lan@umbraco.dk>
2026-03-09 13:16:20 +00:00
5f5ac459d3 Auth: Fix multi-tab auth failures by removing appauth dependency (closes #20873, #21598, #21704, #22022) (#21830)
* Auth: Add minimal PKCE client to replace appauth library (closes #20873)

Introduces UmbAuthClient — a focused OAuth PKCE client that replaces the
forked @openid/appauth library. Uses Web Crypto API for code_challenge
generation and fetch() with credentials:'include' for cookie-based auth.
Zero localStorage usage — PKCE state held in memory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Rewrite auth context with BroadcastChannel and Web Locks

Merges UmbAuthFlow into UmbAuthContext (single consumer, no export).
Replaces localStorage token storage with in-memory session state.

- BroadcastChannel('umb:auth') for cross-tab auth event coordination
- Web Locks API prevents concurrent refresh token race conditions
- postMessage for popup PKCE code_verifier exchange
- sessionStorage for redirect-flow PKCE state (tab-scoped)
- Adds configureClient() for extension developer DX
- Deprecates authorizationSignal (scheduled for removal in Umbraco 19)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Update session timeout controller and SharedWorker

Session timeout controller simplified to take only UmbAuthContext (no
separate authFlow parameter). Observes session$ for timing updates.

SharedWorker now accepts expiresAt timestamp instead of full
TokenResponse. Removes TokenResponse import and TOKEN_EXPIRY_MULTIPLIER.
Sends current session state to new tab connections. Cleans up stale
ports via try/catch on postMessage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Simplify OAuth completion flow and API interceptor

app.element.ts: Remove authorizationSignal wait pattern —
completeAuthorizationRequest() now handles everything. Remove
umbHttpClient.setConfig() call (moved to auth context constructor).

api-interceptor.controller.ts: Replace deprecated authorizationSignal
observer with isAuthorized transition for retrying 401 requests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Deprecate external/openid package and storage constant

Delete all 17 appauth implementation files. Replace index.ts with
deprecated type-only stubs for backwards compatibility — external
consumers can still reference types through v18.

Mark UMB_STORAGE_TOKEN_RESPONSE_NAME as deprecated (scheduled for
removal in Umbraco 19).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Update auth context tests for new implementation

Rewrite tests to cover the new auth context API surface including
configureClient(), getOpenApiConfiguration(), URL generation, lifecycle
management, and bypass auth mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Update extension template to use configureClient() API

Replace manual getOpenApiConfiguration() pattern with the new
configureClient() method on UmbAuthContext — single line to configure
any @hey-api/openapi-ts client for authenticated Management API calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Fix token refresh not firing and adaptive worker timing

Two bugs fixed:

1. makeRefreshTokenRequest() checked expiresAt > now which always
   returned true when the worker fired proactively (before session
   expiry). Changed to compare session reference before/after acquiring
   the Web Lock — only skips if another tab actually refreshed.

2. getLatestToken() checked the full session expiresAt (with 4x
   multiplier) instead of the access token expiry. Split UmbAuthSession
   into accessTokenExpiresAt and expiresAt so each check uses the
   correct threshold.

Also made the worker's buffer and check interval adaptive for short
sessions (< 2 minutes) — buffer is reduced to 25% of session lifetime
and check interval scales proportionally. Fixes the long-standing issue
where very low timeouts caused the buffer to exceed the session.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Propagate sign-out to all tabs via BroadcastChannel

When a user signs out in one tab, broadcast a 'signedOut' message so
other tabs redirect to the logout page. Previously, other tabs only
cleared their in-memory session but continued showing stale data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Route setInitialState through Web Lock to prevent duplicate refreshes

setInitialState() was calling refreshToken() directly, bypassing the
Web Lock. Concurrent API calls (via getLatestToken) also triggered
refresh through the lock. This caused duplicate /token calls — one
outside the lock, one inside — leading to rolling refresh token
invalidation races.

Now setInitialState() goes through makeRefreshTokenRequest() so all
refresh calls are serialized by the same Web Lock.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Close timeout modal when another tab refreshes the session

When the session$ observable emits a new session (e.g. from a
BroadcastChannel update after another tab refreshed), close any open
timeout modal. Previously the modal stayed open with its own countdown,
eventually triggering a spurious logout even though the session was
already extended.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Replace SharedWorker with setTimeout and leader-elected modal

Four improvements from a fresh design review:

1. Remove SharedWorker — replaced with a simple setTimeout in the
   timeout controller. A 15-60s timer is negligible on the main thread,
   and the focused tab's timer is never throttled by browsers.

2. Leader-elected timeout modal — uses Web Lock (ifAvailable) so only
   one tab shows the timeout modal. Non-leader tabs set a fallback
   timeout. When the leader tab resolves the modal, BroadcastChannel
   propagates the result and session$ observer closes stale modals.

3. Peer session request — new tabs ask existing tabs for their session
   via BroadcastChannel before attempting a server refresh. Avoids the
   400 error on fresh sessions and eliminates unnecessary /token calls
   for new tabs in an existing session.

4. Single expiry concept — no more refreshToken vs logout distinction
   from the worker. The controller checks remaining time and decides
   based on keepUserLoggedIn and whether time has fully expired.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Fix timeout modal not showing during buffer zone

The #onSessionExpiring guard used isSessionValid() which returns true
during the warning buffer (before full expiry), preventing the modal
from ever appearing. Replace with expiresAt comparison that only skips
if the session was actually refreshed since the check was scheduled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Set auth header at module level to eliminate timing gap

Move `auth: () => '[redacted]'` into the http-client module-level
config so it's available from first import. Previously, extensions
importing umbHttpClient before UmbAuthContext initialized would send
cookies but not the Authorization header needed by
HideBackOfficeTokensHandler, causing 401s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Bind default interceptors via configureClient()

configureClient() now creates an UmbApiInterceptorController and binds
the default response interceptors (401 retry, error handling,
notifications) alongside auth config. app.element.ts uses this for
umbHttpClient, giving extensions the same middleware pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Fix review findings — stale state, double-broadcast, PKCE cleanup

- clearTokenStorage: also set isAuthorized=false on originating tab
- signOut: inline state clearing to avoid double-broadcasting
  sessionCleared + signedOut; fix dead URL base arg; use
  window.location.origin consistently
- makeRefreshTokenRequest: compare accessTokenExpiresAt values instead
  of object identity for robustness
- completeAuthorizationRequest: only remove sessionStorage PKCE entry
  when state matches (preserve valid entry on mismatch)
- umb-auth-client: warn when expires_in is missing or zero
- configureClient: guard against duplicate calls with WeakSet

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(auth): resolve lint errors and Copilot review issues

- Add eslint-disable blocks around OAuth wire-format URLSearchParams keys
  (client_id, redirect_uri, grant_type, etc.) — these must use snake_case
  per RFC 6749/7636 and cannot be renamed
- Fix optional chaining gap in #openTimeoutModal: store modal ref before
  awaiting so modal?.onSubmit() is safe when modalManager is undefined
- Fix popup Promise never settling: poll for authWindowProxy.closed and
  resolve (cleanup) when the user closes or cancels the login popup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Auth: Deprecate getLatestToken() — always returns '[redacted]' with cookie auth

With cookie-based auth, getLatestToken() always returns '[redacted]'.
The proactive token refresh it performed is no longer needed since:
- The session timeout controller refreshes proactively via setTimeout
- The API interceptor retries 401s automatically

Internal callers (linkLogin, unlinkLogin, server-event, tryXhrRequest)
now use '[redacted]' directly. getOpenApiConfiguration() is kept as the
recommended API for manual fetch calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: adds links to deprecations

* docs: adds deprecation notices

* Auth: Deprecate getLatestToken(), clarify openid stub behavior

- Mark getLatestToken() as deprecated (always returns '[redacted]' with
  cookie auth). Points to configureClient() and getOpenApiConfiguration().
- Inline '[redacted]' in internal callers (linkLogin, unlinkLogin,
  server-event, tryXhrRequest) instead of going through getLatestToken().
- Update getOpenApiConfiguration().token to return '[redacted]' directly.
- Clarify external/openid deprecation header: data classes remain
  functional, handler classes reject because the operations are no
  longer possible with cookie-based auth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: overrides options after applying defaults

* Auth: Supply keepUserLoggedIn from backend via HTML attribute

Instead of fetching keepUserLoggedIn asynchronously from the Management
API after authorization, the server now renders it as a boolean attribute
on <umb-app> from SecuritySettings. This eliminates the timing gap where
the access token could expire before the async preference was fetched,
causing 401s on API calls.

Chain: Index.cshtml → <umb-app keep-user-logged-in> → UmbAuthContext →
UmbAuthSessionTimeoutController. When true, the timeout controller
schedules based on accessTokenExpiresAt (proactive refresh) instead of
expiresAt (full session expiry).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Fix review findings — message storm, PKCE state, spread order

- Fix BroadcastChannel message storm: completeAuthorizationRequest
  was calling #updateSession (which broadcasts sessionUpdate) AND
  separately broadcasting 'authorized'. Other tabs receiving 'authorized'
  called #updateSession again, cascading N² messages. Split into
  #setSessionLocally (no broadcast) and #updateSession (broadcasts).

- Increase PKCE state from 10 to 32 characters for stronger CSRF nonce
  (was ~59 bits, now ~190 bits of entropy).

- Fix tryXhrRequest spread order: ...options was last, allowing callers
  to accidentally override baseUrl/token. Now baseUrl/token come last.

- Remove unused endSessionEndpoint from UmbAuthClientEndpoints interface
  (signOut URL is constructed directly in auth.context.ts).

- Export UmbAuthSession interface for extension developers observing
  session$.

- Add clarifying comments for: anonymous UmbApiInterceptorController in
  configureClient, refresh_token server contract, Web Lock deduplication
  edge case.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Fix review findings — redirect loop, popup leak, navigator.locks fallback

- Fix redirect loop after code exchange by using force=true navigation
  so setInitialState() runs with fresh httpOnly cookies
- Clean up pending popup flows before starting new ones (prevents
  pkceHandler/closedPoll leaks)
- Add navigator.locks fallback for environments without Web Locks
- Clear session on timeOut() to prevent stale in-memory state
- Make AuthorizationError constructor params optional (compat fix)
- Remove dead #previousAuthUrl field
- Add clarifying comments on configureClient and peer session timeout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Wait for both auth and server contexts before initializing SignalR hub

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Use ifAvailable lock to prevent redundant token refresh across tabs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Add default Authorization header to umbHttpClient

The hey-api `auth` callback is only invoked when requests include
`security` metadata (which generated SDK functions do automatically).
Direct `.get()`/`.post()` calls lack this metadata, so the
Authorization header was silently omitted. Adding it as a default
header ensures all requests through umbHttpClient trigger the
server-side HideBackOfficeTokensHandler cookie swap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Auth: Use exclusive lock with freshness check for token refresh

Replaces ifAvailable lock with an exclusive lock that queues tabs.
After acquiring the lock, isSessionValid() checks whether another tab
already refreshed — preventing sequential /token calls when timers
fire slightly offset.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(web): configure umbHttpClient baseUrl before server connection

Move auth context creation and configureClient() before
UmbServerConnection.connect() so that the generated SDK calls
(ServerService.getServerStatus/getServerConfiguration) have a
valid baseUrl on umbHttpClient.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(auth): use object reference comparison in token refresh lock

The isSessionValid() check inside the Web Lock used expiresAt (full
session lifetime), which incorrectly skipped proactive refreshes when
keepUserLoggedIn=true. The timeout controller fires based on
accessTokenExpiresAt, but the full session was still valid at that
point, so the refresh was silently skipped — eventually causing 401s.

Fix: capture the session object reference before entering the lock
queue. Inside the lock, compare references to detect whether another
tab broadcast a sessionUpdate while we were waiting. This correctly
deduplicates multi-tab refreshes while allowing proactive refreshes
to proceed.

Also fixes prettier formatting in UmbAuthClient constructor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: do not assume that any endpoint is authenticated or accepts an Authorization header (this should come from the OpenAPI spec)

* E2E: QA: updated acceptance tests to match the authorization changes in  #21830 (#22021)

Updated tests to the updated auth

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-03-09 12:17:56 +00:00
c48c594e51 Redirect Tracking: Fix segment duplication when domain has a path segment (closes #21763) (#21772)
* Increase precision available to decimal data types.

* Fix redirect URL segment duplication when domain has a path segment.

* Revert accidental commit.

* Fix multiple enumeration

---------

Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
2026-03-09 10:19:21 +00:00
Jacob Overgaard 74c76be952 internal: removes accidentally committed claude settings file 2026-03-09 11:06:22 +01:00
Andy ButlandandGitHub 10ba3519ec Management API: Add server-side validation preventing element types from varying by segment (closes #21643) (#21728)
Validate at management API to prevent create or update of an element type that varies by segment.
2026-03-09 10:47:48 +01:00
Niels LyngsøandGitHub 1958dfe3d2 Content: Only validate selected Cultures (#21361)
* correct comments

* poc

* refactor validation of variants

* refactor to enable parsing alternative validation methods

* only validate selected variants

* validateVariantsAndSubmit method

* refactor for better diff view

* refactor for better diff view

* remove empty comment

* minor refactor

* ensure segment-variants are included when validating

* turn into arrow method

* clean up

* adjust types
2026-03-09 10:23:43 +01:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>iOvergaard
d29b7d26b8 Docs: Reference CLAUDE.md from copilot-instructions instead of duplicating content (#22032)
* Initial plan

* Docs: Update .github/copilot-instructions.md to match CLAUDE.md content

Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>

* Docs: Reference CLAUDE.md from copilot-instructions instead of duplicating content

Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>
2026-03-09 10:00:19 +01:00
c6c8254386 fix: combine external-supplied pickableFilter with internal filter in picker input contexts (closes #21859) (#21989)
* fix: compose user-supplied pickableFilter with internal filter in picker input contexts (#21859)

The openPicker method in UmbDocumentPickerInputContext, UmbMediaPickerInputContext,
and UmbMemberPickerInputContext unconditionally overwrites the user-supplied
pickableFilter with the internal implementation. This prevents package developers
from providing custom filtering logic (e.g., filtering out unpublished items).

The fix composes both filters using a logical AND: the internal filter runs first
(access checks, allowedContentTypes), and if it passes, the user-supplied filter
is also evaluated. This preserves the existing behavior while enabling extensibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: extract _composePickableFilters into base UmbPickerInputContext class

Move duplicated filter composition logic from document, media, and member
picker input contexts into a shared protected method on the parent class.
This reduces cyclomatic complexity in each openPicker override and
eliminates code duplication across the three picker contexts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Rename picker filter helper to _combinePickableFilters

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-03-09 09:55:13 +01:00
Niels LyngsøandGitHub fb5030010c Form Control: only validate if value was changed during focus (#21815)
* poc of minimizing unrelevant validation messages

* remove submit method from interface

* remove call to re-validate, as that is already trigger via `updated`--callback
2026-03-09 08:44:46 +00:00
e8a521eaa0 Backoffice: Export block-single package for external consumers (closes #22044) (#22045)
Export block-single client-side package.

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-03-09 08:23:02 +00:00
Andy ButlandandGitHub 65ad90e248 URL Picker: Fix validation error persisting after link selection (closes #21903, #21454) (#22034)
Fix validation of the multi-URL picker.
2026-03-09 07:50:06 +00:00
Andy ButlandandGitHub 9ceb317003 Media Picker: Show friendly inline validation error when uploading a file with required media type properties (closes #20295) (#22025)
* Align validation failed on image upload messaging with that used for not allowed.

* Trigger build

* Use destructuring.
2026-03-09 08:30:07 +01:00
Niels LyngsøandGitHub 8f42dfe1ee Sorter: Detecting outside drops when browser does not get events (#21664)
Sorter detecting outside drops when browser does not get events from the outside
2026-03-09 08:29:17 +01:00
Johannes LantzandGitHub ba688d4e4c Localization: Add for language picker modal (#22043)
* Added localize.term for umb-language-picker-modal

* Added missing Japanese translation keys for umb-language-picker-modal
2026-03-09 06:41:02 +01:00
Johannes LantzandGitHub cb88588600 Localization: Export dictionary modal (#22038)
* Added localization for Export dictionary modal with Japanese translations

* Replaced unnecessary export key with actions_export
2026-03-07 08:39:01 +01:00
Johannes LantzandGitHub d2b8d02eae Add localize for restore entity action (#22040) 2026-03-06 19:04:03 +01:00
Laura NetoandGitHub 421ad35034 Elements: Split content type validation for create and update (#21906)
* Split content type validation for create and update to allow saving elements no longer permitted in library

* Add integration test for element update after AllowedInLibrary toggle

Verify that ElementEditingService.UpdateAsync succeeds when the content
type's AllowedInLibrary flag is set to false after the element was
created, covering the split validation introduced for create vs update.

* Move content type validation into TryGetAndValidateContentType override

Eliminate redundant content type lookups in CreateAsync and UpdateAsync
by moving the IsElement/AllowedInLibrary check into the
TryGetAndValidateContentType override, which distinguishes create from
update by checking if the model is a ContentCreationModelBase.

* Use Assert.Multiple for element property assertions in update test

* Extract IsAllowedLibraryElement static method for readability
2026-03-06 17:34:00 +00:00
Andy Butland a17aef5af8 Fix sortable property update issue introduced in merge from main. 2026-03-06 17:55:07 +01:00
79ddf45e23 Data Types: Fix collection view references not showing in data type usages (closes #21649) (#21655)
* Fix FindListViewUsages to match ListView key instead of naming convention

* Align GuidUdi creation with FindUsages by adding .EnsureClosed()

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-03-06 11:52:12 +00:00
Nhu DinhandGitHub 32270e7548 E2E: QA Added acceptance tests for allowing folder selection in media entity picker (#21981)
* Added api helper for creating tiptap data type with media folder

* Added ui helper for remove image upload folder

* Updated ui helper for selecting media with name

* Added tests for selecting media link in multi url picker

* Added tests for media picker start node

* Added tests for image upload folder in tiptap data type

* Updated tests for user media start nodes

* Updated tests for user group media start nodes

* Make tests run in the pipeline

* Fixed comment

* Cleaned code

* Added tests for add multiple media start nodes to a user

* Reverted npm command
2026-03-06 10:35:20 +00:00
Jacob OvergaardandGitHub c9b4e1a141 build(deps): bumps @umbraco-ui/uui from 1.17.0 to 1.17.1 (#22029) 2026-03-06 10:08:06 +00:00
Andy Butland 6544c5cbcc Merge branch 'main' into v18/dev 2026-03-06 11:05:17 +01:00
b1b5ce45c8 Backoffice: Add CSP nonce support for inline scripts (closes #21575) (#21581)
* Add CSP nonce support for inline scripts

* Add UseUmbracoCspNonceInjection middleware for NWebsec integration.

* Add unit tests for InjectNonceIntoDirective method.

* Add documented CSP rules to local website so any issues that conflict with these rules are surfaced in local development and testing.

* Test formatting.

* Addressed code review feedback.

* Use tag helper for nonce rendering.

* Apply suggestions from code review

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* Move CspNonceInjectionOptions into it's own file.

* Reduce clutter in Program.cs in local web project, by moving use of documented CSP to an extension method.

* Trigger build

* Exclude CSP from template but keep in local project.

---------

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2026-03-06 11:03:00 +01:00
Andy Butland a0518a0636 Merge branch 'main' into v18/dev 2026-03-06 08:09:37 +01:00
Andy Butland 5e669bb8c7 Merge branch 'main' into v18/dev 2026-03-06 08:08:28 +01:00
Andy ButlandandGitHub b32c944299 Dependencies: Update server-side dependencies to latest patch or minor releases (#21860)
* Update server-side dependencies to latest patch or minor releases.

* Revert and comment upgrade to MailKit.

* Update Microsoft.NET.Test.Sdk to latest minor.
2026-03-06 15:55:00 +09:00
0ead90a7e1 Collection Views: Add sortable value column for custom property sorting (closes #21425) (#21479)
* Migration, model and repository data access for sorting via a sortable field.
Property editor sortable interface and implementation of JSON stored date fields.

* Add migration to populate sortable field for existing date property data.

* Added unit tests for GetSortableValue on datetime property editors.

* Fixed issues raised in code review.

* Re-use code in base from DocumentRepository to avoid additional call to SetEntitySortableValues.

* Move migration to 17.3.

* Fix merge issue.

* Move around migrations so they are in correct order

---------

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
Co-authored-by: Zeegaan <skrivdetud@gmail.com>
2026-03-06 07:40:27 +01:00
Nhu DinhandGitHub 29ef442e99 E2E: QA Added acceptance tests for element picker in content and element (#21745)
* Added tests for content with element picker

* Added tests for element with element picker

* Bumped version

* Renamed tests

* Make tests run in the pipeline

* Bumped version

* Fixed failing tests

* Moved goToBackOffice step to beforeEach

* Moved goToBackOffice to beforeEach

* Fixed comment

* Fixed afterEach() step

* Fixed import

* Fixed

* Reverted npm command
2026-03-06 10:51:52 +07:00
fd905e334e Content picker: Fix dynamic root not firing when inside block list (closes #22008) (#22011)
* Check whether picker is in a block. If so, act as with a new content node.

* re-use isNew flag to not increase complexity for the requestRoot function

* remove random whitespace added by visual studio

* remove ternary to reduce complexity

* move check to backend

* update fallback in SiteDynamicRootOriginFinder as well

* Revert "update fallback in SiteDynamicRootOriginFinder as well"

This reverts commit 0a14aa7393.

* Revert "move check to backend"

This reverts commit ca8b0c06da.

* get content workspace context - analogous to document-block-property-value-user-permission.workspace-context.ts. import interface for getIsNew().

* Use getContext.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-05 15:53:50 +00:00
dd12555e53 Configuration: Make MainDom acquisition timeout configurable (#22013)
* Make the hardcoded time for MainDom acquisition configurable.

* Fixed grammar in comment

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sven Geusens <sge@umbraco.dk>
2026-03-05 15:51:55 +01:00
2ae5582a9e Recycle Bin: Adds destination overrides to restoreFromRecycleBin entity-action kind (#21867)
* feat(recycle-bin): add destination entity overrides to restoreFromRecycleBin kind

Add optional destinationItemRepositoryAlias, destinationItemDataResolver,
and destinationRootEntityType properties to support cross-entity-type
restore (e.g. element restoring into element-folder). Existing document
and media manifests are unaffected as all new properties fall back to
the original values. Also adds element folder restore manifest.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(recycle-bin): extract #resolveDestinationItemName to reduce complexity

Extract resolver logic from setDestination into a dedicated method to
bring cyclomatic complexity under the threshold of 9.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Removed Restore Element Folder From Recycle Bin Entity Action

(This is for a separate PR)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 13:45:59 +01:00
96846799ba Audit Log: Abstracted History Info App into reusable auditLog kind (for documents & media) (#21898)
* feat(content): add shared types and repository interface for audit log kind

Introduces UmbAuditLogTagData types, ManifestWorkspaceInfoAppAuditLogKind manifest
interface, and UmbAuditLogHistoryRepository extending the core audit log repository
with getTagStyleAndText() method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(content): create shared audit log workspace info app element

Reusable element that receives manifest config with auditLogRepositoryAlias
and optional allowedActions. Uses UMB_ENTITY_WORKSPACE_CONTEXT for entity
unique resolution and createExtensionApiByAlias for repository lookup.
Includes reload event listener, pagination, and user avatar caching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(content): add auditLog kind definition and manifest registration

Registers the 'auditLog' kind for 'workspaceInfoApp' extension type,
mapping to the shared element. Includes info-app and audit-log manifest
aggregators.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(documents,media): register audit log repos as extensions and add getTagStyleAndText

- Register UmbDocumentAuditLogRepository and UmbMediaAuditLogRepository as
  extension manifests with type 'repository' and dedicated alias constants
- Add getTagStyleAndText() method to both repositories implementing the
  UmbAuditLogHistoryRepository interface from content package
- Export audit-log types from @umbraco-cms/backoffice/content
- Deprecate getDocumentHistoryTagStyleAndText and getMediaHistoryTagStyleAndText
  utility functions (scheduled for removal in Umbraco 19)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(documents,media): switch audit log info apps to use shared auditLog kind

- Update document and media info-app manifests to use kind: 'auditLog'
  with meta configuration (auditLogRepositoryAlias, allowedActions)
- Include repository manifests in document and media audit-log aggregators
- Wire audit-log kind manifests into the content package
- Deprecate UmbDocumentHistoryWorkspaceInfoAppElement and
  UmbMediaHistoryWorkspaceInfoAppElement (scheduled for removal in Umbraco 19)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(documents,media): add `api` exports to audit log repositories

Required for the extension registry API loader pattern which expects
either a default or named 'api' export from the module.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Linting

* refactor(content): extract renderHistoryItem to reduce cyclomatic complexity

Splits the repeat callback out of #renderHistory into a dedicated
#renderHistoryItem method, reducing the method's cyclomatic complexity
below the threshold of 9.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(content): throw error when workspace entity unique is missing

Restores fail-fast behavior for missing entity unique in audit log
requests, matching the original document/media implementations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(audit-log): move getTagStyleAndText to UmbAuditLogRepository as optional method

Removes UmbAuditLogHistoryRepository interface and adds optional
getTagStyleAndText() to UmbAuditLogRepository in core. Moves tag
types to core/audit-log and adds a default type parameter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(audit-log): export repository alias constants from package entry points

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Linting and tidy-up

* Fixes canceled Rollback modal error

* Removed the `allowedActions` property

* feat(content): formalize `auditLogAction` extension type

Add proper TypeScript interfaces, default kind, and dedicated element
for the `auditLogAction` extension type, replacing the previous
untyped usage that relied on `ManifestEntityAction`.

- Define `ManifestAuditLogAction` and `MetaAuditLogAction` interfaces
- Create `umb-audit-log-action` element using `uui-button` (suited for
  the audit log info-app header, unlike `uui-menu-item`)
- Register default and contentRollback kind manifests
- Move contentRollback audit-log-action kind to the content module
- Separate document-specific audit-log-action manifest into its own file

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-03-05 12:44:40 +00:00
0ec334e252 fix(media): allow focal point to be set to null in image cropper (#21340)
* fix(media): allow focal point to be set to null in image cropper

- Updated UmbImageCropperPropertyEditorValue type to allow null for focalPoint
- Changed component state to use null as default instead of { left: 0.5, top: 0.5 }
- Replaced logical OR (||) with nullish coalescing (??) to preserve null values
- Updated reset function to set focalPoint to null
- Added null handling in all rendering and calculation logic
- Components now default to center (0.5, 0.5) for display when focalPoint is null

Fixes #21273

* refactor(media): extract logic from initializeCrop to reduce function size

- Extracted mask dimension calculation into #calculateMaskDimensions
- Extracted mask style application into #applyMaskStyles
- Extracted image scale calculation into #calculateImageScales
- Extracted image position calculation into separate methods:
  - #calculateImagePositionWithCoordinates (for existing crops)
  - #calculateImagePositionWithFocalPoint (for focal point positioning)
- Extracted image style application into #applyImageStyles
- Extracted zoom level update into #updateZoomLevel

Reduces #initializeCrop from 72 lines to 33 lines, meeting CI/CD threshold of 70 lines.

Related to #21273

* refactor(media): replace primitive parameters with interfaces to fix code quality warnings

- Created ViewportDimensions interface to group viewport width/height
- Created MaskDimensions interface to group mask dimensions and position
- Created ImageDimensions interface to group image dimensions and position
- Refactored all functions to use interface objects instead of multiple primitives
- Reduced #calculateImageDimensionsAndPosition from 5 args to 2
- Reduced #calculateImagePositionWithCoordinates from 5 args to 2
- Reduced #calculateImagePositionWithFocalPoint from 4 args to 1

Fixes primitive obsession (85.7% -> reduced) and excessive function arguments warnings.

Related to #21273

* fix(media): update modal value interface to allow null focal point

- Updated UmbImageCropperEditorModalValue interface to allow null for focalPoint
- Added explicit null handling when assigning focalPoint in onChange handler

Fixes TypeScript build error where null focalPoint was not assignable to non-nullable type.

Related to #21273

* Refactor image cropper focal-point handling

* Set defaultFocalPoint to null in test file.

* Default focalPoint to null and adjust checks.

---------

Co-authored-by: Francluob <francluob.dev@gmail.com>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: Emma L Garland <1649855+emmagarland@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>
2026-03-05 10:57:50 +00:00
Andy ButlandandGitHub 59bbcaa129 Memory Management: Dispose IDisposable resources correctly in four internal classes (#22014)
* Dispose event listener created in InMemoryAssemblyLoadContextManager.

* Use using to dispose ICryptoTransform in MemberPasswordHasher.

* Dispose CancellationTokenSource in DatabaseServerMessenger.

* Dispose deserialized JsonDocument in CacheInstructionService.

* Use try/finally to ensure dispose.
2026-03-05 11:44:44 +01:00
Niels Lyngsø db9cbcb457 Merge branch 'main' into v18/dev 2026-03-05 11:07:26 +01:00
Niels Lyngsø 2e75da2df9 Chore: decrease threshold to 15 bidirectional imports 2026-03-05 11:07:12 +01:00
Niels Lyngsø d04f8d9029 fit unit test types 2026-03-05 11:04:41 +01:00
Niels Lyngsø ee68fb393c fix unit test types 2026-03-05 11:04:17 +01:00
Niels LyngsøandGitHub 71ea6f4a93 Breadcrumb variant-name logic improvment (#21617)
* Adjust name logic to adapt to current-culture and not display invariant name as inherited

* refactor
2026-03-05 09:28:15 +00:00
Andy Butland c4d09893cd Merge branch 'main' into v18/dev 2026-03-05 09:22:54 +01:00
337139f7b2 Data Access: Modifies entity repository sibling queries to support custom database p[oviders (closes #21852) (#21671)
* quote table, column and alias names with SqlSyntaxProvider methods in raw sql

* refactoring private methods into new file as internal methods,
refactor new extensions into another file

* refactor GetAlias method

* Double check the change

* improve code health

* change new static classes into public static partial class NPocoSqlExtensions

* resolve some Copilot review suggestions

* revert Copilot suggestion because it decreases code health

* revert test

* compare in with LOWER, change two methods from private to protected in UmbracoDatabaseFactory

* revert Query.cs in this PR

* Refactor for code health and fixing raw sql

* divers small issues fixed

* refactor two methods to respect the DRY pricipal

* update IQuery interface

* clean up

* revert refactoring for CodeScene

* delete obsolete Test

* rename method

* remove new methods and updates, which are not relevat for this PR

* prepare for additional states in the future

* don't mix string building methods

* fix SQL injection danger

* fix test for reverted methods

* another SqlSyntax issue

* fix update

* fix reverted changes

* restore change for this PR

* restore change for this PR

* fix merge bug

* update formating

* extend ISqlSytax for database independent autoIkrement feature

* fix DTOs, extend ISqlSyntax

* fix tests

* revert

* updates

* diverse SqlSyntax and NPoco related updates for custom databse providers

* fix names

* squash merge v173/20453-DTO-attributes-fixed into v173/20453-final-sql-syntax-fixes

* merge

* add default implementation to interface

* fix tests

* fix PrimaryKey for multi columns

* test fix

* Resolve the issues with SqlSyntaxProvider for SQLite. If executed correctly, a single test would reveal the problem.

* add another test

* revert changes which causes even more issues

* fix SQL syntax

* fix column const naming

* ensure column const names from v17.2

* add comment for change

* Update src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeTemplateDto.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* resolve review comments

* Make ReferenceMemberName consistent across all DTOs (use constants defined on the referenced DTO).

* Ensure [ExplicitColumns] attribute exists on all DTOs.

* Ensure we consistently use PrimaryKeyColumnName over PrimaryKeyName.

* Fix further inconsistency to use only TemplateNodeIdColumnName.

* Fixed trailing whitespace.

* Restored primary key constraint name on ContentVersionCleanupPolicyDto (it doesn't seem in scope of PR to remove this).

* Removed the confusing PrimaryKeyColumnName constants for multi-column primary key DTOs where the constant refers to only one of the key columns.

* ReferenceMemberName needs to be a C# property name, so it's safer to use nameof.

* Comment fix.

* Amended accessibility modifiers.

* revert unnecessary changes

* revert unnecessary changes

* revert unnecessary changes

* fix SQLite escape variants

* fix typo

* simple (typo) fixes of Copilot review comments

* solve another Copilot review comment

* improve comments and minimise changes

* add an detailed change comment

* resolve review and revert all integration test. Tests changes will be done in the PostgreSqlProvider-npocp branch like some unit tests.

* remove InsertWithSpecialAutoIncrement()

* update WhereIn() for case sensitive databases

* fix special char in test comment

* throw exception for invalid values

* remove values type check

* add extra check

* resolve review comments

* revert more changes with question

* refine method SiblingsSql of EntityRepository, add another AndSelect() method overload to NPocoSqlExtensions.

* resolve review

* fix replacement

* trigger new pipeline build

* trigger new pipeline build

* Added comment explaining why withAlias: false is needed.

* Add additional tests around sibling retrieval.

* Add tests for the AndSelect overloads.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-05 09:21:40 +01:00
Niels LyngsøandGitHub 684d08b631 Content Rollback: error handling (#22018) 2026-03-05 07:49:52 +00:00
Jacob Overgaard 040735b1c1 build: optimises azure static builds in order not to consume too many environments 2026-03-05 08:32:25 +01:00
Jacob Overgaard e1cc6926ab build: optimises azure static builds in order not to consume too many environments 2026-03-05 08:31:30 +01:00
f7bab4521b Content Rollback: Abstracted rollback into reusable contentRollback entity action and modal kinds (#21939)
* Content Rollback: Abstract document rollback into reusable entity action and modal kinds

Create shared `rollback` entity action kind and modal kind in the content package,
enabling reuse for upcoming entity types (e.g., Elements in v18). The document
rollback now uses these kinds via manifest meta, while old APIs are preserved
with @deprecated annotations for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Content Rollback: Address PR review feedback

- Add validation for manifest meta in rollback modal element, throwing
  descriptive errors if rollbackRepositoryAlias or detailRepositoryAlias
  are not configured
- Remove non-null assertions in favor of validated manifest access
- Fix deprecated requestVersionByDocumentId to delegate through the
  generic requestVersionById interface method
- Remove unused requestVersionByDocumentId deprecated method (original
  method was requestVersionById, not requestVersionByDocumentId)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Renamed "rollback" to "contentRollback"

for class names and manifest kind.

* Content Rollback: Move repo aliases to entity action meta; remove modal kind

Move rollbackRepositoryAlias and detailRepositoryAlias from the modal
kind manifest meta to the entity action meta, passing them as modal
data. Remove the contentRollback modal kind entirely and register the
modal element directly. Introduce UMB_CONTENT_ROLLBACK_MODAL token so
the entity action no longer needs a configurable rollbackModalAlias.
Deprecate document-level modal constants in favor of content-level ones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fixed linting errors

* eslint missed an export! 🤦

* refactor(backoffice): rename UMB_ENTITY_ACTION_ROLLBACK_KIND_MANIFEST to UMB_ENTITY_ACTION_CONTENT_ROLLBACK_KIND_MANIFEST

Address PR review feedback to include "Content" in the manifest constant name for consistency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:09:56 +01:00
Andy ButlandandGitHub 31aa6e5847 Decimal Property Editor: Align step precision with database storage (closes #22003) (#22004)
Align decimal property editor precision with storage.
2026-03-04 13:33:35 +01:00
Andy Butland d92502b212 Merge branch 'main' into v18/dev 2026-03-04 12:15:01 +01:00
bd52e95a10 Management API: Add item ancestors endpoints returning item response models (#21874)
* Create item endpoints that return ancestor IDs for a given collection of entity IDs.

* Return item models instead of just IDs.

* Use async methods.

* Use NamedItemResponseModel for container ancestor endpoints.

* Simplify the usage of ItemAncestorService - use less assumptions about structure and use generic mapping for basic response models.

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-03-04 12:04:46 +01:00
Andy Butland 6b00925a6a Merge branch 'main' into v18/dev 2026-03-04 11:55:57 +01:00
8b9bfb3a65 URL and Alias Caches: Optimize for invariant documents (#21558)
* Optimize (memory usage, database storage, and processing time) document URL and alias cache for invariant documents.
Store invariant content with NULL languageId instead of duplicating records for each language.

* Additional integration tests verifying aspects of changed functionality.

* Implement and test that URLs and aliases are updated when a content type changes from variant to invariant or vice versa.

* Tidied up migration.

* Corrected file name.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Further updates from code review, resolved warnings.

* Use rebuild key defined in constant in migration.

* Handle possibility of custom URL providers generating different URL segments per culture.

* Resolve breaking change.

* Handling breaking change in DocumentUrlDto.

* Tidied up code comments

* Fix issue where URL aliases on variant content with a shared property were not being recorded.

* Tidy up comment.

* Fix breaking change in nullability.

* Fix breaking change in nullability (2).

* Revert "Fix breaking change in nullability (2)."

This reverts commit c77a37c855.

* Fix failing integration tests.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-04 11:55:09 +01:00
Andy Butland b9142ad728 Merge branch 'main' into v18/dev 2026-03-04 11:54:49 +01:00
Nhu DinhandGitHub e89cc4961b E2E: QA Updated failing acceptance tests to match the UI changes (#22002)
* Updated ui helper for verify the file uploads

* Updated tests due to test helper changes

* Updated tests for block due to UI changes

* Added comment for the failing tests
2026-03-04 17:34:51 +07:00
Andreas ZerbstandGitHub 7f9f58f559 E2E: QA: added acceptance tests for preview (#21967)
* Added preview helper

* Added preview helpers

* Added preview tests

* Updates based on comments

* reinitialize the preview locators for the pop up preview page

* Cleaned up based on comments

* Update smokeTest command in package.json
2026-03-04 10:27:13 +00:00
Nhu DinhandGitHub b71c2e53b7 E2E: QA Added acceptance tests for reference tracking info tab of elements (#21949)
* Added tests for element reference tracking in info tab

* Removed tags

* Make all ElementReferenceTracking tests run in the pipeline

* Moved goToBackOffice step to beforeEach

* Updated import file

* Make tests run in the pipeline before merging

* Fixed npm command

* Revert npm command
2026-03-04 10:11:46 +00:00
598a2186d7 Elements: Treat local elements as global elements (#21795)
* Make local and global elements behave the same (use the same implementation)

* Await async calls, don't fire-and-forget

* Fix the remaining unit tests

* Flush static fields on friendly published extensions before starting tests

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-03-04 10:05:52 +01:00
Andreas Lykke BorgandGitHub c313e6f112 List view: Added labels entity bulk action buttons (#21964)
* Added labels to checkboxes and buttons and fixed checkbox alignments

* Reverted u200B as label in checkboxes
2026-03-04 08:47:42 +00:00
24a01df870 Content Picker: Pass preview flag to published content cache lookups (closes #21972) (#21975)
* Ensure content picker correctly handles preview state.

* Return null for unresolvable content picker values, preserve routing properties.

* Apply suggestions from code review

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

---------

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2026-03-04 09:31:12 +01:00
fcdfb9e588 E2E: QA: Merge moved testhelpers/builders from 17 to 18 (#21970)
* Moved helpers/builder from v18

* Updated existing helpers/builder

* Updated ui helper for updating property editor in document type

* Fixed failing tests

* Revert changes to package-lock

* Cherry pick latest updates from main

---------

Co-authored-by: Nhu Dinh <hnd@umbraco.dk>
2026-03-04 12:02:24 +07:00
8ae768d4eb Update badge icon (#21911)
* Change the badge icon svg content

* Updates "badge" icon with "id-card.svg"

---------

Co-authored-by: Pasang Tamang <45009265+pasangtamang@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-03-04 04:15:46 +00:00
59fd3938a2 Content Types: Fix API response for cancelled delete operation (#21758)
* fix(core,api,web): fix backoffice UI errors on notification cancellation

- Fix ContentTypeServiceBase.DeleteAsync() to use PublishCancelableAsync
  directly instead of delegating to the sync Delete() method, which
  silently swallowed cancellation and always returned Success.
- Extract shared deletion logic into private PerformDelete() method
  to keep both Delete() and DeleteAsync() DRY.
- Mark ProblemDetails with notificationsDeliveredViaHeader extension
  when Umb-Notifications header carries event messages, preventing
  the frontend from showing duplicate error toasts.
- Add notificationsDeliveredViaHeader to UmbProblemDetails type and
  skip redundant ProblemDetails notification in try-execute controller.
- Add integration test for DeleteAsync cancellation detection.

* fix(core,api,web): fix backoffice UI errors on notification cancellation

- Fix ContentTypeServiceBase.DeleteAsync() to use PublishCancelableAsync
  directly instead of delegating to the sync Delete() method, which
  silently swallowed cancellation and always returned Success.
- Extract shared deletion logic into private PerformDelete() method
  to keep both Delete() and DeleteAsync() DRY.
- Mark ProblemDetails with notificationsDeliveredViaHeader extension
  when Umb-Notifications header carries event messages, preventing
  the frontend from showing duplicate error toasts.
- Add notificationsDeliveredViaHeader to UmbProblemDetails type and
  skip redundant ProblemDetails notification in try-execute controller.
- Add integration test for DeleteAsync cancellation detection.

fix: #12636

* fix(core): reduce PerformDelete arguments and trim LOC

Address CodeScene quality gate failures:
- Reduce PerformDelete from 5 to 4 parameters by resolving
  EventMessages internally via EventMessagesFactory.Get()
- Trim lines of code to stay within the 1000 LOC threshold

* refactor(core): extract obsolete container methods into partial class

Split ContentTypeServiceBase into two partial class files to address
CodeScene's "Lines of Code in a Single File" quality gate (1007 > 1000).

The #region Containers block was chosen for extraction because all its
methods are already marked [Obsolete] and scheduled for removal in
Umbraco 18, replaced by IContentTypeContainerService and
IMediaTypeContainerService. The region is fully self-contained with no
inbound calls from the rest of the class.

This is a compile-time only change — partial classes produce identical
IL output. No public API, behavior, or binary compatibility impact.

* Revert "refactor(core): extract obsolete container methods into partial class"

This reverts commit 6fd8fd23f6.

* Pass eventMessages from the caller into PerformDelete instead of being re-obtaining from the factory.

* Use try/finally in test to ensure clean-up.

* Restore removed comments.

* Revert client-side updates.

* Revert client-side updates (2).

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-03-03 17:41:05 +00:00
Andy ButlandandGitHub c8564f33e7 Health Checks: Add check for imaging HMAC secret key (#21991)
* Added healthcheck for Imaging:HMACSecretKey configuration setting.

* Added healthcheck for Imaging:HMACSecretKey configuration setting.

* Address code review feedback.

* Removes unnecessary test.

* Use service in healthcheck.
2026-03-03 17:17:15 +00:00
Mads RasmussenandGitHub d7d3e4a613 Backoffice Toast Notifications: prevent double toast notifications on cancelled server operation statuses (#21993)
Ignore server-notified operation statuses
2026-03-03 17:46:57 +01:00
ad6813ca4a Search field: Added aria-label and name to search input for accessibility (closes #21938) (#21962)
* Add aria-label and name to search input for accessibility

- Add aria-label attribute to search input using localized placeholder text
- Add name attribute ("search-input") to provide form field identification
- Fixes Google Console warning about missing id/name on form field
- Improves WCAG 3.3.2 compliance (Labels or Instructions)
- Improves WCAG 2.5.3 compliance (Form input identifiable names)

Closes #2193

* Reused localized label

* Tidy-up/linting

---------

Co-authored-by: Emma L Garland <1649855+emmagarland@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-03-03 16:46:12 +00:00
Andy ButlandandGitHub 317319cd9f Imaging Configuration: Auto-generate HMAC secret key for new installs (#21976)
* Auto-generate HMAC secret key for imaging on new installs.

* Address code review feedback.

* Log results of configuration operations.

* Refactored to use the Attempt pattern.
2026-03-03 16:21:54 +00:00
Andy ButlandandGitHub f58894eb8a Media Picker: Allow custom folder types when creating inline folders (closes #21850) (#21959)
* Allow custom folder types when creating from media picker.

* Adjust selector padding.

* Corrected call to await.

* Addressed feedback from code review.
2026-03-03 15:41:42 +00:00
Jacob Overgaard b00840e147 build(login): syncs lockfile 2026-03-03 16:20:43 +01:00
Jacob Overgaard f2473f7f74 build(login): syncs lockfile 2026-03-03 16:19:08 +01:00
Jacob Overgaard 57c4339dd1 build(login): syncs lockfile 2026-03-03 16:18:50 +01:00
Jacob Overgaard 673d97c19b build(login): syncs package files 2026-03-03 16:17:06 +01:00
Jacob Overgaard ad6606e048 build(login): syncs package files 2026-03-03 16:16:40 +01:00
Andy Butland 32acc62cde Merge branch 'main' into v18/dev 2026-03-03 15:44:45 +01:00
059c25fb3e Media Workspace: Fix collection view showing root items after creating new folder (closes #21700) (#21753)
* Set entity unique before scaffold processing to fix collection view for new media folders.

* Instead of moving setUnique() earlier in the provider, fix the consumers to observe the unique observable rather than reading synchronously.

* Addressed code review point on context observation.

* implement satisfies type check

* minor refactor

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-03-03 13:47:39 +00:00
f954a3fe74 Templating: Prevent editing of templates and partial views in production runtime mode (closes #21564) (#21600)
* Prevent save of partial view file when using runtime production mode, and verify for partial views and templates with integration tests.

* Display warning when templates and partial views are not editable in the backoffice.

* Share styles.

* Validate at the partial view API whether updates are allowed based on production runtime mode.

* Add similar checks for templates, handling case where metadata updates are allowed.

* Add integration tests for verifying behaviour in production mode.

* Fix the breaking changes on the constructor of the service classes.

* Use IOptions (we don't need live updates for this setting).

* Addressed code review feedback.

* Add IsProductionMode private property on both updated services.

* Move create template check to validate method.

* Remove entity actions create/delete/rename for templates and partial views whilst running in production mode.

* Addressed code review feedback.

* include server in condition name

* move tag to bottom right corner of workspace

* introduce info modal

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-03-03 13:24:41 +00:00
Andy ButlandandGitHub 0340d8c37d Block editors: Make block editors read-only when document is trashed (closes #21973) (#21982)
* Make block editors read-only when document is trashed.

* Hide update button on block non-line workspace if document is read-only.
2026-03-03 13:06:15 +00:00
Andy ButlandandGitHub d224251098 Backoffice Search: Default global search to current section (closes #21621) (#21636)
* Default the global search to the current section.

* Refactor to use meta element to target a section alias.
2026-03-03 13:45:11 +01:00
Andreas ZerbstandGitHub 27d03c3632 E2E: QA: Added acceptance tests for dynamic roots (#21966)
* Added tests

* Updated tests

* Updated smokeTest script, will be reverted

* Fixes based on comments

* Fixes

* Reverted command
2026-03-03 12:40:38 +00:00
Andy ButlandandGitHub 49eba63172 Hybrid Cache: Resolve IsPublished() returning false in preview mode (closes #21983) (#21985)
Resolve IsPublished() returning false in preview mode for published content.
2026-03-03 12:58:43 +01:00
Laura Neto c568db2704 Re-generate Umbraco.Tests.AcceptanceTest/package-lock.json 2026-03-03 12:45:34 +01:00
88d07d5c3f Content Type: Introduce Entity Content Type Entity Context (#21817)
* introduce entity content type entity context

* introduce for document, media, member workspaces and trees

* provide for Document card

* add conditions and reorganize

* Stabilize entity content-type condition tests

* Set media content-type context in item card

* rename example

* Remove entity-type condition and refs

* add example

* Refactor entity-action components to consume UMB_ENTITY_CONTEXT instead of requiring entityType/unique props.

* update stories

* Add UmbEntityContext to collection item elements

* add tests

* Add context boundary to entity collection items

* Add test for entity context boundary

* Update umb-entity-collection-item-element-base.element.test.ts

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update umb-entity-collection-item-element-base.element.ts

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update umb-entity-collection-item-element-base.element.test.ts

* Update umb-entity-collection-item-element-base.element.ts

* Remove entity props from umb-entity-actions-bundle

* Revert "Update umb-entity-collection-item-element-base.element.ts"

This reverts commit 9e4ef79150.

* Provide entity context on host and update tests

* Revert "Provide entity context on host and update tests"

This reverts commit f618a8216e.

* fix lint errors

* Test entity context boundary for collection items

* Update entity-content-type-unique.condition.test.ts

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-03 11:30:11 +00:00
8e662db487 Tiptap RTE: Table node-view refactor to fix popover menus (closes #20614) (#21696)
* Tiptap Table: fix popover positioning for row and column grips

Refactored the table extension to use a proper container structure
and separate popovers for row and column context menus.

Key changes:
- Added UmbTableView with block container, inner table container,
  widgets container, and overlay container structure
- Created TableHandlePlugin to manage grips and popovers centrally
- Changed from single shared popover to separate row and column
  popovers, fixing the issue where column menu always appeared
  at the first column position
- Updated CSS styles to support the new container structure
- Added proper cleanup when tables are removed from the editor

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Deprecates `UmbBubbleMenu` extension

No longer used internally.
There were issues with the popover and Tiptap editor state.

* Tiptap Table node-view refactor

* Exports `UmbTableView`

* Handles `mouseleave` event

* Adds readonly guard and dynamic grip offset for table handles

Prevents grips/popovers from appearing and dispatching transactions
when the editor is in readonly mode. Replaces hardcoded 16px container
offset with dynamic bounding rect computation to stay in sync with CSS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Uses TableMap for cell indices instead of DOM child indexes

Resolves cell row/column via ProseMirror position resolution and
TableMap.findCell, which correctly handles merged cells (colspan/rowspan)
instead of relying on DOM child indexes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-03 11:13:48 +00:00
6535a9e753 Tiptap RTE: Adds actionButton kind for toolbar extensions (closes #21682) (#21703)
* Improvement: Use `when` callback parameter in tiptap toolbar disabled button

Use the callback parameter from Lit's `when` directive instead of a
non-null assertion to access the icon value.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Feature: Add `actionButton` kind for tiptap toolbar extensions

Create a new `actionButton` kind that uses the disabled button element,
replacing manual `element` overrides in the Unlink, Undo, and Redo
toolbar manifests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Improvement: Add dedicated element for `actionButton` tiptap toolbar kind

Addresses review feedback by creating a proper `umb-tiptap-toolbar-button-action`
element for the `actionButton` kind instead of reusing the `-disabled` element.

- Uses `api.isDisabled()` for the disabled state (not `!isActive`)
- Types manifest correctly via generic on base class
- Makes base `UmbTiptapToolbarButtonElement` generic so subclasses can
  specify their manifest kind
- Deprecates `umb-tiptap-toolbar-button-disabled` (scheduled for removal in v19)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Improvement: Add base API class for `actionButton` toolbar extensions

Introduces UmbTiptapToolbarActionButtonApiBase with a default isDisabled
implementation that returns !isActive(editor), so third-party extensions
get meaningful disabled state without needing to override isDisabled.

Updates undo, redo, and unlink APIs to use the new base class, removing
their redundant isDisabled overrides. Adds a comment explaining the
implicit re-render dependency in the action button element.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:00:27 +00:00
Andy Butland fa6c5d0537 Merge branch 'main' into v18/dev 2026-03-03 11:44:10 +01:00
005241ee4a Upload Field: Show filename after file upload (closes #21587) (#21887)
* fix(media): display filename in upload field preview

Add visible filename text to the file and image upload field preview
components. Previously, the file preview only showed an icon and the
image preview only used the filename as invisible alt text.

The filename is extracted from the File object when available (blob
URLs during upload), falling back to the last path segment for
persisted server paths.

Closes #21587

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(media): display filename in audio, video, and SVG upload previews

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(media): move filename display to parent upload field with file-info bar

Move filename rendering from 5 individual preview components into the
parent input-upload-field element. The filename and remove action now
share a bordered bar below the preview. Filename is plain text during
upload (blob URL) and a clickable link to the file when saved.

Reverts preview components to their original state (preview only).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style updates

* link style adjustment

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-03-03 10:19:02 +00:00
Andy ButlandandGitHub fcbedf2d6f Service registration: Allow running Umbraco with different combinations of backoffice, website and delivery API (closes #21622) (#21630)
* Add support for running website without backoffice.

* Add support for running delivery API without website or backoffice.

* Reverted unncessary idempotent checks on individual builder extensions.

* Integration tests for service registrations.

* Integration HTTP tests for service registrations.

* Tidy up and code review feedback.

* Remove unnecessary null check.

* Ensure models builder references are added to attempt to resolve the deliver API setup.
2026-03-03 09:49:21 +01:00
Laura NetoandGitHub 62d9a002f7 Elements: Add missing documentation endpoint attributes (#21979)
Add missing EndpointSummary and EndpointDescription attributes to element recycle bin restore controllers
2026-03-03 08:47:01 +01:00
Andy Butland 8b59e8eb3b Merge branch 'main' into v18/dev 2026-03-03 08:06:31 +01:00
43f91ef47e Account logout: Handle revocation request for cookie-stored back-office tokens (closes #21918) (#21944)
* Handle revocation request for cookie-stored back-office tokens

* Addressed feedback from code review.

* Use OpenIddict constant instead of hardcoded string

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-03-03 06:37:07 +01:00
d2a6bd0a40 Media Picker: Allow folder selection in media entity picker (closes #21885) (#21895)
* Allow folder selection in media entity picker

* Also handle user and user group media root node picker.

* Allow file selection for users and user groups, fixing failing E2E test.

* Changed media start nodes for user/user group to select folders only

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-03-03 05:12:23 +00:00
Andy ButlandandGitHub 0e6a04c4fc Public Access: Handle inherited protection gracefully in modal dialog (closes #21965) (#21971)
Handle inherited public access gracefully in modal dialog.
2026-03-02 21:08:52 +00:00
Andy ButlandandGitHub 6a00d61337 Media Dropzone: Clarify error messages when file upload is not allowed (closes #21506) (#21708)
* Improve messaging on failed file uploads.

* Introduced utility for getting the extension from a file and addressed other code review comments.
2026-03-02 18:35:51 +00:00
Niels Lyngsø eec6a27cca Merge branch 'main' into v18/dev
# Conflicts:
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
#	tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/User/ContentStartNodes.spec.ts
#	tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/User/MediaStartNodes.spec.ts
2026-03-02 14:00:47 +01:00
1d3216e08c Members: Enable sorting on member table and order member groups by name (closes #21960) (#21963)
* Add support for member sorting by member type.

* Make the backoffice member table sortable by the supported fields.

* Sort member groups by name.

* Fixed linting issue.

* Use UmbDirection for sort direction

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-03-01 21:59:39 +01:00
eaed6cb0c9 Accessibility: Added title attribute for icon in content types (#21956)
* Fix missing <title> attribute for Icons in document types in backoffice

* Move the title attribute to uui-button from umb-icon.

* Removed color option from lable and title. Added prefix "Change icon:" in the title. Prefix managed from the localization.

* Improve icon tooltip accessibility and i18n in content type header

  - Add defensive check in #iconTitle to avoid "undefined" text when icon is unset
  - Move colon separator from translation strings to component template
  - Use consistent label for both title and aria-label on icon button
  - Add Spanish and Italian translations for changeIcon key

* Fix failing test by using an exact match for a label.

---------

Co-authored-by: Pasang Tamang <45009265+pasangtamang@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-27 18:51:27 +00:00
bbab9f8006 Move/Duplicate: Filter tree picker based on allowed parent rules. (#21646)
* Document Types returns a list of allowed parent keys

* Media types included

* Add selectable filter for duplicate action based on allowed parents.

* Add optional selectable filter provider support to move action.

* Add selectable filter provider for move action in documents.

* Add selectable filter provider for move action on media.

* Optimize filter providers by using allowedAsRoot property directly.

* Refactor document move action to use repository for selectable filter.

* Move media filter logic from provider to repository .

* Centralize allowed-parent logic in data sources.

* Remove document item lookup from duplicate action.

* Simplify custom filter assignment in move action.

* Remove unused import.

* Rename getSelectableFilter method in document duplicate action..

* Refactor move to action for documents.

* Refactor of media move to action.

* Refactor duplicate action and remove unused imports.

* Clean up.

* Use .js extension for media tree type import

* Export move action and fix imports.

* add interfaces for type safety

* local implementations

* make linter happy

* make linter happy

* Filter out current node in MoveTo action

* Return error instead of throwing on fetch

* Use typed getters for structure data sources

* remove unused

* Add UmbTreeItemModel typing to move-to actions

* align paramater naming

* Defer move repository lookup until after modal

* Fetch type data concurrently with Promise.all

---------

Co-authored-by: NillasKA <kramernicklas@gmail.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-02-27 15:36:09 +00:00
Sven GeusensandGitHub 8340ff015e Integration Tests: Fix null reference errors (#21953)
* Dont blow up GetTestOptions when inside testfixtures

* Dont blow up Reference resolving when working with proxies

* Improve GetAssemblyFolders nullability

* More verbosity
2026-02-27 16:27:08 +01:00
82f805abca Management API: Add document and data types tree search endpoints (#21628)
* Messy implementation of documenttypes and datatypes

* Formatting and move service injection to constructor

* cleanup and bubble up new constructor

* Allow folder or item only searches

* feedback pr & subsequent refactoring

* Apply review suggestions

* Update openapi file

* Used constant, resolved minor layout warnings.

* Fix parent key lookup in tree search to check both folders and items.

* Remove TreeItemKind.None from flags enum.

* Add TODOs for removing the default implementation on the interfaces.

* Add permission integration tests.

* Update OpenApi.json.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-27 14:44:23 +00:00
Andy ButlandandGitHub 53615e3d86 Repeatable Textstring: Skip empty strings in validation and persistence (closes #21912) (#21915)
* Skip empty strings in repeatable textstring validation and persistence.

* Override RequiredValidator for repeatable textstring to treat all-empty arrays as no value.
2026-02-27 15:18:23 +01:00
Nathaniel NunesandGitHub db1cf01342 Accessibility: Add tooltips to block grid entry actions (#21958)
#20422 - Add tooltips to block grid entry actions for improved accessibility
2026-02-27 14:21:37 +01:00
Niels LyngsøandGitHub a7164d56f2 Slider Preset: make it easier to read the code (#21955)
refactor to make easier to read
2026-02-27 13:06:18 +01:00
Nhu DinhandGitHub 32d7f528f1 E2E: QA Updated AllowEditInvariantFromNonDefaultIsTrue tests to match the UI changes (#21950)
* Updated ui helper for add block list button

* Make AllowEditInvariantFromNonDefaultIsTrue tests run in the pipeline

* Removed .skip since the issue is resolved

* Fixed tests for submit an empty URL in RTE property

* Make TiptapToolbar tests run in the pipeline

* Reverted npm command
2026-02-27 08:44:24 +00:00
Mads RasmussenandGitHub 6f2cd9ec8e Backoffice Performance: Add inflight request deduplication to item data request managers (#21767)
* add inflight request cache to all item request managers

* Use inflight request cache for item data

* Add tests for Item Data Request Manager
2026-02-27 08:38:50 +01:00
f3adc14a72 Performance: Optimize handling of content type updates (#21910)
* Claude's suggestions

* Rewrite for tags based hybrid cache eviction and optimize the converted, in-memory cache eviction

* Replicate cache invalidation/flushing optimizations for the media cache service

* Do not perform Examine re-indexing for "other" changes on content types

* Clean up TODOs

* Use configured batch size for indexing, and use cached structure for checking publish status

* Default implementations of new interface methods to prevent breaking changes

* Clean out more TODOs

* Refactor logic to extension methods

* Add missing notification handlers to cache tests

* Add additional test coverage.

* Remove OnChange from settings for transient notification handler.

* Adds a migration to clear the hybrid cache to ensure all items are tagged by content type.

* Clear all converted content on type change in auto models builder mode.

* Apply the same fix for data type updates.

* Apply the same fix for data type updates (2).

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-27 08:29:51 +01:00
Lars-Erik AabechandGitHub b0756cb626 Integration tests: Re-virtualized CustomMvcSetup (#21947)
Re-virtualized CustomMvcSetup

Someone finalized my beautiful "last-hook-in-setup-for-mvc-things". 🥹
2026-02-27 08:26:27 +01:00
5958198f0d Fix: Increase size of modal listing property editors (#21825)
* Changed the modal size to medium data type picker modals.

* Updated the icon and label alignment so that icon always align vertically top and label in each starts from same position.

* Linting

* Adds `justify-items: center` for "Create new" button icon

---------

Co-authored-by: Pasang Tamang <45009265+pasangtamang@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-02-27 05:08:21 +00:00
39170fbf66 Entity Signs: Enable entity signs for media items (closes #21786) (#21832)
* Add support for entity signs on media items.

* Code linting tweaks

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-02-26 22:51:48 +00:00
1719e5d07f Member Group Picker: Add server-side paging to public access modal (closes #21790) (#21834)
* Add pagination to the member group picker.

* Linting

...and use of `when` directive ;-)

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-02-26 21:42:39 +00:00
7a07c1160f User History: Improve recent history display with better labels and de-duplication (#21656)
* Improve recent history display with better labels and de-duplication.

* Addressed code review comments.

* Handle race condition where wrong item would get updated.

* Uses Lit `repeat` directive

* Reverted breaking-changes

added deprecation comments (for removal in v19)

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-02-26 19:58:36 +00:00
Nhu DinhandGitHub 3b68fef220 E2E: QA Added acceptance tests for global elements (#21608) 2026-02-26 17:28:21 +00:00
Andreas ZerbstandGitHub 35fb0a74d7 E2E: Move test helpers and builders into the acceptance test project and publish as @umbraco/acceptance-test-helpers (#21773)
* Move testhelpers and builder into the acceptance test project

* Updated imports in tests

* Updated readme

* Updated postinstall to exclude setting up config

* added a cleanup when npm packing

* update tsconfig path mapping to @umbraco/acceptance-test-helpers

* Added dist to git ignore

* Adds separate README files for npm and GitHub
 README.md: contributor-focused (test docs)
 README.npm.md: consumer-focused (package docs)
 cleanse-pkg.js swaps them during npm pack

* Updated to swap READMEs on npm pack. So the consumer README is the one being released

* Add npm publish pipeline for @umbraco/acceptance-test-helpers

* Configure package.json for npm publishing as @umbraco/acceptance-test-helpers

* Updated missing imports

* Cherrypicked helper changes

* Updated tests

* Updated name of builder

* added tslib

* Fixed test

* Renamed

* Add nbgv version step for test helpers npm package

* Fixes based on comments

* More fixes

* Removed unnecessary imports

* Fix naming of storage_state_path

* Added recommend for storage state

* Create console file if not present
2026-02-26 17:58:42 +01:00
950b5861c7 Block List: consistent spacing between blocks (#21750)
* simpler and more consistent css for block list and block single

* adjust spacing only for default views

* adjust inline and support for Block Grid

* simplify gap css for Grid Entries

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-02-26 16:48:15 +00:00
1d9d44a470 Create new folder on enter in media picker (#20648)
* Create new folder on enter in media picker

* Move CSS properties and change value for placeholder.

* Add localization key for labels and placeholder.

---------

Co-authored-by: Emma L Garland <emmagarland77@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-02-26 14:19:11 +00:00
0780c22002 Templates: Add optional Central Package Management support to UmbracoProject and UmbracoExtension templates (#21641)
* Adding CPM into Umbraco Project

* Adding CPM for UmbracoExtension

* remove CPM from umbraco templates

* remove change from readme

* update readme for umbracoproject

* Adding CPM options to Umbraco Project and Umbraco Templates

* update name param

* make central to default option

* Update templates/UmbracoExtension/Umbraco.Extension.csproj

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update templates/UmbracoExtension/.template.config/template.json

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update templates/UmbracoProject/.template.config/template.json

Co-authored-by: Andy Butland <abutland73@gmail.com>

* add PackageManagement into Visual studio display

* Apply suggestions from code review

* Fix ascii art and typo.

* Remove trailing commas in template.json files.

* Aligned casing and grammar between package management choices.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-26 13:33:39 +00:00
Niels LyngsøandGitHub 7c031f8ae4 is-routable-context-condition (#21428) 2026-02-26 13:29:58 +00:00
e9a6d52814 Collection: Provide UmbEntityContext for entity collection item elements (#21847)
* Add UmbEntityContext to collection item elements

* add tests

* Add context boundary to entity collection items

* Add test for entity context boundary

* Update umb-entity-collection-item-element-base.element.test.ts

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update umb-entity-collection-item-element-base.element.ts

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update umb-entity-collection-item-element-base.element.test.ts

* Update umb-entity-collection-item-element-base.element.ts

* Revert "Update umb-entity-collection-item-element-base.element.ts"

This reverts commit 9e4ef79150.

* Provide entity context on host and update tests

* Revert "Provide entity context on host and update tests"

This reverts commit f618a8216e.

* Test entity context boundary for collection items

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-26 14:25:18 +01:00
Niels LyngsøandGitHub 27618a3621 Block Editors: Align create label (#21731)
Use 'add content' to align with the create modal and other Block Editors
2026-02-26 13:31:19 +01:00
e0bb8f294e E2E: QA Added acceptance tests for for scheduled publishing (#19794)
* Cleaned up

* Make ScheduledPublishing tests run in the pipeline

* Updated npm command

* Increased timeout

* Updated npm command

* Addec console log to test in the pipeline

* Make tests run in the pipeline

* Removed step to verify that the document is published since it doesn't work in the pipeline - only works locally

* Update npm command

* Fixed tests

* Fixed comments

* Removed unnecessary comments

* Revert npm command

---------

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-02-26 10:47:50 +00:00
Engiber LozadaandGitHub 1cb8b2c8d2 Media Picker Modal: Fix missing tooltip on media items in picker modal. (#21913)
* Set title attribute on media card in picker.

* Add title attribute to uui-card-media in media inputs.
2026-02-26 09:55:50 +01:00
Andy Butland 92ec78086d Merge branch 'main' into v18/dev 2026-02-26 07:06:34 +01:00
Andy Butland 2f381fe700 Fix after merge. 2026-02-26 07:05:51 +01:00
Andy Butland c3fc3c949e Merge branch 'release/17.2.1' 2026-02-26 06:59:27 +01:00
Andy ButlandandGitHub 0a40fe7364 Data Types: Use configured ValueType when creating Label data types (closes #21853) (#21914)
Use configured ValueType when creating Label data types.
2026-02-26 12:44:07 +09:00
cf9c2908b4 Elements: Add permission-based filtering to element tree endpoints (#21729)
* Add permission-based filtering to element tree endpoints

The element tree endpoints now filter results based on the current
user's browse permissions via a new IElementPermissionFilterService,
mirroring the existing document tree behavior.

Also extracts shared filtering logic from DocumentPermissionFilterService
into a PermissionFilterServiceBase to avoid duplication.

* Add unit tests for ElementPermissionFilterService

* Replace document-specific inheritdoc with neutral XML docs in PermissionFilterServiceBase

* Fix GetPermissionsAsync to use the provided objectTypes parameter instead of hardcoded Document type

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-02-25 15:13:42 +00:00
a8526429ba Cache: Ensure local cache instructions count towards last synced ID (#21907)
* Ensure local cache instructions count towards last synced ID

* Add obsoletion message to the interface.

* Fixed failing integration tests, then refactored them so they call and test the non-obsolete method.

* Rework the solution to retain existing functionality

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-25 15:03:26 +00:00
Andy Butland 040f27c673 Bumped version to 17.2.2. 2026-02-25 15:03:55 +01:00
Laura NetoandGitHub 765a3b2968 Tests: Set AllowedInLibrary on element content type in permission tests (#21908)
Set AllowedInLibrary on element content type in permission tests

The GetElementPermissionsCurrentUserControllerTests were failing because the
test setup created an element content type without setting AllowedInLibrary
to true. The ElementEditingService.TryGetAndValidateContentType method now
requires both IsElement and AllowedInLibrary to be true for element creation.
2026-02-25 15:02:12 +01:00
Laura NetoandGitHub 89c7bb356b Elements: Replace block keys on element copy and save (#21814)
* Handle element saving and copying notifications in complex property editors

Extend ComplexPropertyEditorContentNotificationHandler to also handle
ElementSavingNotification and ElementCopyingNotification, ensuring that
block property key replacement (BlockList, BlockGrid, RichText) is
applied to elements the same way it is for content.

* Add integration tests for element copy with block editors

Test that block keys are regenerated and block structure is preserved
when copying elements with BlockList, BlockGrid, and RichText editors,
for both invariant and culture-variant content.
2026-02-25 14:06:55 +01:00
Andy Butland 023c08fcdb Merge branch 'main' into v18/dev 2026-02-25 11:30:01 +01:00
Andy ButlandandLaura Neto c9c16d2605 URL Info: Fix invariant content URLs missing under non-default language domains (closes #21866) (#21883)
* Show correct URLs for invariant content under non-default language domains.

* Use configured domain hosts instead of request host for fallback URL filtering.

* Addressed feedback from code review.

* Fixed code warnings.

* Update file references in integration test csproj.

* Simplify invariant URL culture filtering by determining cultures upfront

Instead of querying all cultures and post-processing to remove irrelevant
URLs, determine the relevant cultures before the loop by checking which
domains are assigned to the content's ancestor path.

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-02-25 11:28:39 +01:00
df952c92a2 URL Info: Fix invariant content URLs missing under non-default language domains (closes #21866) (#21883)
* Show correct URLs for invariant content under non-default language domains.

* Use configured domain hosts instead of request host for fallback URL filtering.

* Addressed feedback from code review.

* Fixed code warnings.

* Update file references in integration test csproj.

* Simplify invariant URL culture filtering by determining cultures upfront

Instead of querying all cultures and post-processing to remove irrelevant
URLs, determine the relevant cultures before the loop by checking which
domains are assigned to the content's ancestor path.

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-02-25 11:27:26 +01:00
Andreas ZerbstandGitHub 29233a3455 QA: E2E: Added v18/dev so it runs on the nightly test pipeline (#21902)
Removed v15dev and added 18dev to nightly pipeline
2026-02-25 10:22:04 +00:00
Andy Butland 7b97bdd0ef Merge branch 'main' into v18/dev 2026-02-25 09:41:15 +01:00
Andy Butland 62eb91675d Database Cache: Fix full database cache rebuild dropping variant and composed property values (closes #21863, #21882) (#21890)
* Resolve full database cache rebuild dropping variant and composed property values

* Addressed feedback from code review.
2026-02-25 08:01:25 +01:00
Andy ButlandandGitHub 09206a62ac Database Cache: Fix full database cache rebuild dropping variant and composed property values (closes #21863, #21882) (#21890)
* Resolve full database cache rebuild dropping variant and composed property values

* Addressed feedback from code review.
2026-02-25 07:42:23 +01:00
Andy ButlandandGitHub d3b3661efc Dotnet Templates: Update default UmbracoVersion template value using MSBuild target (closes #21889) (#21893)
Apply version replacement to extensions template.
2026-02-25 01:31:53 +00:00
b1ca081613 Image cropper and file upload: Implemented automatic naming of uploaded file (closes #21764) (#21775)
* Added a feature to have automatic naming of the uploaded media files as per requested by #21764

* Replaced UMB_PROPERTY_DATASET_CONTEXT by UMB_NAMEABLE_PROPERTY_DATASET_CONTEXT to ensure proper use of isNameablePropertyDatasetContext

* style: fix import ordering to match eslint rules

Co-Authored-By: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>

* style: order furthest relative imports first

Co-Authored-By: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>

---------

Co-authored-by: Pasang Tamang <45009265+pasangtamang@users.noreply.github.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-02-24 13:11:26 +00:00
Andy ButlandandGitHub 15a75b1c5d Document Repository: Batch document IDs in GetContentSchedulesByIds to avoid SQL parameter limit (closes #21865) (#21868)
* Update GetContentSchedulesByIds to retrieve data in groups to avoid overrunning the SQL parameter count.

* Protect against duplicate retrieval if duplicate IDs are provided.
2026-02-24 11:45:57 +01:00
Andy ButlandandGitHub 5df7ff184f Backoffice Search: Discard stale search results when switching providers (closes #21784) (#21849)
* Discard stale search results when switching providers.

* Applied change from code review.
2026-02-24 10:44:17 +00:00
Andy Butland 5642c624d8 Remove legacy Windows path length checks and related tests (#21884)
Removed explicit 260-character path length checks from PhysicalFileSystem.GetFullPath and deleted associated unit tests. Updated tests to focus on path normalization and validity, and improved path assertions for clarity and cross-platform compatibility. No longer enforce or test for legacy Windows path length restrictions.
2026-02-24 11:21:18 +01:00
Andy ButlandandGitHub 7c0e332001 Content Picker: Fix dynamic root resolution for new unsaved documents (closes #21870) (#21880)
Correct resolution of dynamic root for new unsaved documents.
2026-02-24 09:46:45 +00:00
8b018c8178 Entity Data Picker: Add text filter feature toggle for Collection Data Sources (#21732)
* Add data-source package and integrate in input-entity-data

* Add optional description to collection items

* introduce extension picker data source

* fix problem with shallow copy because of js module in object

* nest manifest data

* Hide pagination when all items are shown

* Add a fallback page size

* merge extension insight code with extension code

* clean up

* Add optional description support to default item ref

* Revert "Add data-source package and integrate in input-entity-data"

This reverts commit e02881e8b6.

* fix post merge

* add input-extension utilizing input-entity-data

* proxy value and selection

* add todo

* temp hardcode config

* add typed config model

* Support multiple extension types in filters

* Use extensionTypes filter and deprecate type

Standardize extension collection filtering by introducing extensionTypes and phasing out the old type field.

* More explicit type name

* Expose allowedExtensionTypes as a @property on UmbInputExtensionElement

* Add text filter support for entity data picker

* remove reexport as this is not public available

* remove unused

* clean up

* clean up

* Add storage and getter for allowedExtensionTypes

* Inline collection view alias and remove constant

* Update vite.config.ts

* Update manifests.ts

* Update extension.picker-data-source.ts

* add tests for extension picker data source

* change to an observable feature config

* make feature object optional

* add unit tests

* Reference condition class directly in manifests

* clean up observers if data source type changes

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-02-24 09:30:51 +00:00
0f8b38c1b4 Razor Template Debugging: Allow Umbraco projects to work with the Razor cohosting editor (#21861)
* Allow Umbraco projects to work with the Razor cohosting editor

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-24 08:59:54 +01:00
Andy ButlandandGitHub 24540e11e0 Content Type: Fix null property description displaying as "null" string (closes #21873) (#21879)
Ensure an empty string is rendered for a null property description rather than a "null" string.
2026-02-24 07:44:36 +00:00
a2e3b929bd UmbracoExtension template: Use runtimeConfigPath for automatic auth (#21838)
* UmbracoExtension template: Use runtimeConfigPath for automatic auth

Use hey-api's runtimeConfigPath to pre-configure the generated client
by copying umbHttpClient's config (baseUrl, credentials, auth) at
initialization time. This eliminates the need for entrypoint auth setup
via consumeContext/getOpenApiConfiguration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: updates extension with newly generated SDK files

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 07:33:31 +00:00
Andy Butland 21597fa2f8 Merge branch 'main' into v18/dev 2026-02-24 06:57:14 +01:00
9976b9f523 Examine: Keep track of rebuilding in memory on startup and move use of LongRunningOperationService to user triggered rebuilds (#21821)
* Keep track of rebuilding in memory

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Remove comment

* Revert back to original with lock

* Apply suggestion from @Zeegaan

* Remove unused

* Adress review comments

* Improve in-memory rebuild tracking for index rebuilder.

* Add cross-server rebuild status tracking via ILongRunningOperationService.

* Ensure index is used in operations, to allow rebuild of different indexes concurrently.

* Use Task.Delay.

* Resolve breaking change in constructor.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-24 06:56:03 +01:00
Andy Butland 336039f963 Merge branch 'main' into v18/dev 2026-02-24 06:40:18 +01:00
Laura NetoandGitHub c7125967c9 Elements: Add scheduled publishing support for elements (#21796)
* Add scheduled publishing support for elements

Move PerformScheduledPublish from IContentService to the shared
IPublishableContentService<T> interface so both documents and elements
support scheduled publishing.

Filter ClearSchedule and HasContentForRelease/Expiration queries in
PublishableContentRepositoryBase by NodeObjectTypeId to prevent document
and element schedules from interfering with each other.

Update ScheduledPublishingJob to process both document and element
schedules, and add integration tests verifying cross-entity isolation.

* Simplify ScheduledPublishingJob.ExecuteAsync

Extract duplicated scheduled publishing logic into a generic helper
method and include the entity type in the log message.
2026-02-23 20:12:00 +01:00
3e0a3ff1ea Content Version Cleanup: Include element versions in the background cleanup job (#21839)
* Add element version cleanup to the content version cleanup background job

The existing ContentVersionCleanupJob only cleaned up document versions.
Element versions were left to accumulate despite having the same cleanup
service infrastructure available. This extends the job to also clean up
element versions using the same configuration toggle and schedule.

* Use PascalCase for structured logging names.

* Fixed code warnings and duplicate line breaks.

* Cleaned up usings.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-23 18:58:15 +00:00
Mads RasmussenandGitHub f934c88911 Extension: Introduce extension core module and umb-input-extension element (#21705)
* Add data-source package and integrate in input-entity-data

* Add optional description to collection items

* introduce extension picker data source

* fix problem with shallow copy because of js module in object

* nest manifest data

* Hide pagination when all items are shown

* Add a fallback page size

* merge extension insight code with extension code

* clean up

* Add optional description support to default item ref

* Revert "Add data-source package and integrate in input-entity-data"

This reverts commit e02881e8b6.

* fix post merge

* add input-extension utilizing input-entity-data

* proxy value and selection

* add todo

* temp hardcode config

* add typed config model

* Support multiple extension types in filters

* Use extensionTypes filter and deprecate type

Standardize extension collection filtering by introducing extensionTypes and phasing out the old type field.

* More explicit type name

* Expose allowedExtensionTypes as a @property on UmbInputExtensionElement

* remove reexport as this is not public available

* remove unused

* clean up

* clean up

* Add storage and getter for allowedExtensionTypes

* Inline collection view alias and remove constant

* Update vite.config.ts

* Update manifests.ts

* Update extension.picker-data-source.ts

* add tests for extension picker data source
2026-02-23 16:54:26 +00:00
Andy Butland 79b3058a96 Bump version to 17.2.1. 2026-02-23 16:39:49 +01:00
23062762aa Media: Mark touchstart handler as non-passive using @eventOptions decorator (#21845)
The touchstart handler on the image cropper focus setter needs to call
preventDefault() to prevent scrolling during focal point drag. Use Lit's
@eventOptions({ passive: false }) decorator to explicitly declare this,
resolving the browser warning about non-passive event listeners.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-02-23 11:00:26 +01:00
e5ec2a9f11 Examine: For indexing in the RTE, replace all HTML tags with spaces to make sure word boundaries are preserved (#21797)
* For indexing in the RTE, replace all HTML tags with spaces to make sure wqord boundaries are preserved. Closes #21778

* Trim the returned string and adjust test cases to match new expected output #21778

* Address review comments:
- Updated XML docs
- Removed trimming in unit tests
- Moved HTML strip implementation to an extensions method

* Removed redundant regexes

* Address comment formatting

* Address failed tests by not replacing multiple characters if the replacement is String.Empty to preserve existing behavior

* Remove unnecessary partial and using.

* Add tests for introduced overload of StripHtml, fix found issues with replacement regex, then optimised by removing second regex and replaced with string operations.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-23 10:54:20 +01:00
9279a951c1 Routing: Fix umbracoUrlName being ignored in DefaultUrlSegmentProvider on culture-variant content when property is invariant (closes #16791) (#21735)
* Fix umbracoUrlName not working on multi sites

* update documentUrlServiceTests

* Use "is false" for false comparison

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-23 09:30:20 +00:00
dc1821e86f Cache Refreshers: Fix change tracking for content types (#21856)
* Fix change tracking for content types

* Update src/Umbraco.Core/Services/ContentTypeEditing/ContentTypeEditingServiceBase.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Updated comments for ContentTypeChangeTypes

* Clean up comments

* Revert "Clean up comments"

This reverts commit e17904c202.

* Actually clean up comments

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-23 07:56:32 +00:00
Laura NetoandGitHub fa95f956a0 Elements: Add audit log retrieval endpoint and UI support (#21777)
* Add missing AuditType.Copy audit log for element copy operations

Make the abstract Copy method in ContentEditingServiceBase async and
accept a Guid userKey instead of int userId, allowing the element
copy implementation to use the audit service directly. Add the
missing _auditService.AddAsync(AuditType.Copy, ...) call in
ElementEditingService.CopyAsync to match the document equivalent
in ContentService.Copy.

* Fix copy audit log to record against the original element

The copy audit entry was being logged against the new copy's ID
instead of the original element's ID, inconsistent with how
documents handle copy audit logging.

* Add audit log retrieval endpoint for elements and wire up frontend

Add GET /{id:guid}/audit-log endpoint following the document audit
log pattern. Wire up the existing frontend data source to call the
new API, add element-specific localization strings, and remove the
unsupported sort audit type.
2026-02-23 08:43:36 +01:00
30aade8e3a Unit Testing: Add comprehensive coverage for BlockEditorVarianceHandler (#21706)
* test: add comprehensive test coverage for BlockEditorVarianceHandler

- Add tests for AlignPropertyVarianceAsync method (collection alignment)
- Add tests for AlignedExposeVarianceAsync method
- Add edge case tests for segment variations
- Add tests for multiple items and deduplication scenarios
- Remove TODO comment

Fixes #21706

* refactor: reduce code duplication in BlockEditorVarianceHandler tests

- Add CreateBlockListValue helper method to eliminate repeated setup code
- Remove redundant test cases to reduce duplication
- Consolidate similar tests while maintaining essential coverage

Fixes code duplication issues reported in PR #21706

* fix: correct assertion in AlignPropertyVarianceAsync_Removes_NonDefault_Culture_Values test

When culture variance is disabled (ContentVariation.Nothing), the culture
should be set to null, not preserved. This matches the behavior tested in
Removes_Default_Culture_When_Culture_Variance_Is_Disabled test.

* fix: always deduplicate expose entries in AlignExposeVariance

Deduplication should always occur at the end of AlignExposeVariance,
even when no alignment is needed. This ensures duplicate expose entries
are removed regardless of whether variance alignment occurred.

* fix: remove expose entries when ContentData is missing

Expose entries that don't have matching ContentData should be removed
from the expose list. This ensures data consistency and prevents orphaned
expose entries.

* test: add 8 additional test cases for BlockEditorVarianceHandler

Adds comprehensive test coverage for:
- Culture assignment scenarios
- Segment variation handling
- Multiple ContentData items
- Edge cases (missing element types, no matching expose)
- Variation matching scenarios

* refactor: eliminate code duplication in BlockEditorVarianceHandler tests

Extract common test patterns into helper methods:
- CreatePropertyValues: Creates property values from configuration tuples
- CreateBlockPropertyValues: Creates block property values with alias/culture/segment
- CreateBlockItemVariations: Creates block item variations from tuples
- ExecuteAlignPropertyVarianceAsync: Executes AlignPropertyVarianceAsync with common setup
- ExecuteAlignedExposeVarianceAsync: Executes AlignedExposeVarianceAsync with common setup
- ExecuteAlignExposeVariance: Executes AlignExposeVariance with common setup
- SetupAlignedExposeTest: Sets up test data for AlignedExposeVarianceAsync tests

This eliminates copy-pasted code patterns across multiple test methods.

* refactor: eliminate duplication in AlignedPropertyVarianceAsync tests

Extract common test setup into ExecuteAlignedPropertyVarianceAsync helper method.
This eliminates duplication in:
- Assigns_Default_Culture_When_Culture_Variance_Is_Enabled
- Removes_Default_Culture_When_Culture_Variance_Is_Disabled
- Ignores_NonDefault_Culture_When_Culture_Variance_Is_Disabled
- AlignedPropertyVarianceAsync_Returns_As_Is_When_Variation_Matches

* fix: add missing using statements for Task, IList, IEnumerable, Func

* fix: correct Assert.ThrowsAsync usage - await the task when accessing exception

* fix: await Assert.ThrowsAsync directly to get exception

* remove: AlignPropertyVarianceAsync_Throws_When_PropertyType_Is_Null test

* fix: mock should return null for unknown content types in AlignExposeVariance test

* Revert production code changes - keep only test additions

* Remove bug-fix verification tests - moved to PR #21801

* refactor: consistently use CreateBlockListValue helper in all tests

* test: restore AlignExpose_Can_Handle_Variant_Element_Type_With_All_Invariant_Block_Values test

* docs: clarify why mock returns null for unknown content types

* refactor: use configuration class to reduce argument count in CreateBlockPropertyValues

* fix: add missing closing brace for Assert.Multiple block

* fix: remove leftover merge conflict marker

* fix: remove duplicate method definitions

* Remove unused code and usings. Encapulate BlockPropertyValueConfig. Fix code warnings.

* Standardise test naming, order of methods and use of Assert.Multiple.

* Complete test coverage with additional tests for AlignedExposeVarianceAsync.

---------

Co-authored-by: root <root@dragon.second>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-23 07:22:28 +00:00
Niels LyngsøandGitHub 13a095934e CurrentUserModal: use getContext instead of consumeContext (#21843)
use getContext instead of consumeContext
2026-02-20 15:11:10 +01:00
Nathaniel NunesandGitHub f01ea69919 Accessibility: Add title attributes to buttons in block list entry and property editor UI (#21842)
#21841 - Add title attributes to buttons in block list entry and property editor UI for better accessibility
2026-02-20 13:03:38 +00:00
Niels Lyngsø ba83cc1006 Merge branch 'main' into v18/dev 2026-02-20 13:48:48 +01:00
4cb81b2e0e Document Workspace: Update document status on publish and unpublish (closes #21650) (#21668)
* Ensure document status shown in the Infor workspace view is up to date after unpublish and save/publish operations.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Further feedback from code review.

* Fix false-positive pending changes after save and publish by ensuring the property value preset builder reconstructs objects with the same property key order.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-02-20 13:42:03 +01:00
Laura Neto 17dd0757d3 Merge branch 'main' into v18/dev 2026-02-20 13:38:06 +01:00
3ac5986f19 Fix: BlockEditorVarianceHandler deduplication and orphaned expose entries (#21801)
* Fix: BlockEditorVarianceHandler deduplication and orphaned expose entries

- Fix deduplication not running when no alignment needed
- Fix orphaned expose entries not removed when ContentData missing

Fixes #21799
Fixes #21800

* Update src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorVarianceHandler.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Fix indentation and add bug-fix verification tests

* Code tidy, use helpers in tests.

---------

Co-authored-by: root <root@dragon.second>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-20 12:01:32 +00:00
Yari MariënandGitHub 8b8b1c607a Localization: Added missing translation values for field label on create member form (#21835)
fix(member-info-screen): added translation for confirmPassword to fix visible translation key on member view/info
2026-02-20 12:52:05 +01:00
Laura NetoandGitHub e02a3d452c Repository Caches: Fix GUID cache key prefix in PublishableContentRepositoryBase (#21836)
Fix GUID repository cache key prefix in PublishableContentRepositoryBase

The merge of the GUID cache key collision fix (9ea0520) applied
IContent-specific changes from DocumentRepository's nested class, but
in v18/dev this code lives in the generic base class. Two issues:

- EntityByGuidReadRepository.GetCacheKey used the "uRepo_" prefix
  while GuidReadRepositoryCachePolicy looks up entries with "uRepoGuid_",
  causing PopulateCacheByKey to insert under a key the policy never finds.
- PersistUpdatedItem cleared GetGuidKey<IContent> instead of
  GetGuidKey<TEntity>, so ElementRepository would clear the wrong key.
2026-02-20 11:35:52 +00:00
Andy ButlandandGitHub e9ba715e62 Server Events: Invalidate client-side cache for composing types on composition deletion (#21831)
* Invalidate client-side cache after removal of composed content type.

* Address feedback from code review.
2026-02-20 15:12:57 +09:00
0ce31e0793 Media Querying: Fix MediaAtRoot() to use IMediaNavigationQueryService root keys (#21807)
* Add media navigation support to PublishedContentQuery

Introduced IMediaNavigationQueryService as a dependency and updated constructors to resolve it. Refactored ItemsAtRoot to accept a navigation query service, enabling MediaAtRoot to retrieve root media items via navigation queries. ContentAtRoot and MediaAtRoot now use the appropriate navigation query service for root item retrieval.

* Add IMediaNavigationQueryService support to content query

Extended PublishedContentQuery and ContentFinderByConfigured404 to accept and use IMediaNavigationQueryService alongside IDocumentNavigationQueryService. Updated constructors and service registrations to ensure both navigation services are available for enhanced content and media navigation scenarios.

* Add obsolete constuctors and expand PublishedContentQuery tests

Introduce [Obsolete] constructor overloads for PublishedContentQuery and ContentFinderByConfigured404 to support legacy usage, scheduled for removal in Umbraco 19. Refactor ItemsAtRoot for clarity. Significantly expand PublishedContentQueryTests with comprehensive unit tests covering constructor validation, Content/Media overloads, root item retrieval, and search functionality, including paging, ordering, and culture context. Add test helpers and mocks to improve test coverage and reliability.

* Fixes to constructor overloads.

* Re-organise tests into unit and integration (so the former, that don't need integration setup, will run more quickly).

* Remove low value integration tests.

---------

Co-authored-by: Fabian Beier <Fabian.Beier@aa-g.de>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-19 11:57:03 +00:00
Niels Lyngsø 33a30c38dc Merge branch 'main' into v18/dev 2026-02-19 10:50:40 +01:00
bb567524d4 Media Collection: Introduce Entity Actions for cards (#21816)
* refactor to use the collection item extension point

* Add actions slot to media collection item card

* Set actions slot button background in media card

* Update src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.context.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-19 10:34:14 +01:00
a1627b82d3 RTE Link Picker: Fix media selection to allow items not permitted at root. (#21678)
* Exclude media folders and remove media-type filtering.

* Remove unused import.

* general clean up

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-02-19 09:30:43 +00:00
Andy Butland 9a0309ac62 Merge branch 'main' into v18/dev 2026-02-19 10:03:10 +01:00
Andy Butland 588e93ae75 Re-ordered methods in class. 2026-02-19 09:40:29 +01:00
Andy ButlandandGitHub 9ea0520a46 Repository Caches: Fix GUID read repository cache key collision causing GetAll failures (closes #21756) (#21762)
* Fix GUID read repository cache key collision with int-keyed repositories.

* Remove GUID read repository for templates.

* Ensure GUID read repository cache keys are invalidated.

* Further optimisation of by GUD GetAll reads.

* Move default repository cache timespan to a centralised constant.

* Further use of centralised constant.

* Add GetGuidKey<T>(Guid id) and update callers to use it.
2026-02-19 07:58:07 +00:00
Andy Butland 4ca0d041f2 Merge branch 'release/17.2' 2026-02-19 07:46:06 +01:00
Andy Butland 51e91c88ae Bump version to 17.2.0. 2026-02-19 06:49:24 +01:00
Niels Lyngsø b2af37a149 Merge branch 'release/17.2'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
2026-02-18 15:39:11 +01:00
Jacob OvergaardandGitHub 725a0322ed build(deps): bumps @umbraco-ui/uui to 1.17.0 (#21765) 2026-02-18 14:59:45 +01:00
Mads RasmussenandGitHub 7f1e30a22e Document Collection: Enable Entity Actions on cards (#21802)
* Use card view kind for Document Collection

* Remove unused UmbUserDetailModel import

* Update document-collection-item-card.element.ts

* combine elements

* render actions
2026-02-18 13:29:26 +00:00
Mads RasmussenandGitHub f7661a310f Document Collection: Reuse card view kind (#21791)
* Use card view kind for Document Collection

* Remove unused UmbUserDetailModel import

* Update document-collection-item-card.element.ts
2026-02-18 12:48:21 +01:00
Niels Lyngsø 31ffc9ff02 Merge branch 'main' into v18/dev 2026-02-17 10:37:21 +01:00
Andy ButlandandGitHub 48a431eeec Packaging: Fix package migration plans re-running all steps when a new step is added (closes #21730) (#21734)
* Ensure package migration steps only run once by moving the override of IgnoreCurrentState to true to the derived AutomaticPackageMigrationPlan, where it's needed.

* Add integration test to verify the fix.

* Fix failing integration test (the test migration plans were leaking outside of the new test, and being picked up by the DI container for other tests.
2026-02-17 10:17:50 +01:00
8e911d728d Elements: Add AllowedInLibrary flag to content types with dedicated endpoint (#21723)
* Add AllowedInLibrary flag to content types

Add a new boolean property AllowedInLibrary across all layers to
indicate whether a content type is allowed in the library. This is
only meaningful for element types (IsElement = true).

Changes span the core domain model, Management API request/response
models, persistence DTOs/mappers/factories, and a database migration
to add the column to the cmsContentType table.

* Enforce AllowedInLibrary in ElementEditingService.CreateAsync

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(api): add AllowedInLibrary filter to document type search endpoint

Add allowedInLibrary query parameter to GET /document-type/search,
following the same pattern as the existing isElement filter. The old
SearchAsync overload without the parameter is preserved as a default
interface method and marked obsolete (scheduled for removal in v19).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(api): regenerate OpenApi.json and backoffice client types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(api): make search query parameter nullable for document type search

Allow the document type search endpoint to be called without a text
query, enabling filter-only usage (e.g. filtering by isElement and
allowedInLibrary without requiring a search term).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(api): replace search allowedInLibrary filter with dedicated endpoint

Revert the search endpoint changes (IContentTypeSearchService, controller)
and instead add a dedicated GET /document-type/allowed-in-library endpoint
that follows the AllowedAtRoot pattern. This ensures IContentTypeFilter
support and a cleaner API separation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(api): add integration tests for GetAllAllowedInLibraryAsync and AllowedInLibraryDocumentTypeController

Add service-level tests verifying correct filtering by IsElement + AllowedInLibrary, pagination, and IContentTypeFilter integration. Add controller-level authorization tests for the allowed-in-library endpoint.

* Map allowedInLibrary through content type data sources

Add allowedInLibrary to UmbContentTypeModel and map it consistently
across document, media, and member type data sources for scaffold, read,
create, and update operations.

* Add AllowedInLibrary support to test builders and set it in all element tests

ElementEditingService.CreateAsync checks contentType.AllowedInLibrary and
returns NotAllowed if false. All element test types were missing this flag,
causing test failures. Adds IWithAllowedInLibraryBuilder interface, extension
method, and sets AllowedInLibrary=true on all element type creation in tests.

* Also enforce IsElement check when creating elements in the library

* Set IsElement and AllowedInLibrary on ElementPublishingServiceTests content types

* Remove AllowedInLibrary from document type tree item response model

The AllowedInLibrary property is not relevant for tree items and is not
used by the frontend. This removes it from the tree item model, its
mapping in the tree controller, and regenerates the OpenAPI spec and
TypeScript client accordingly.

* Refactor element content type validation into base class override

Make TryGetAndValidateContentType protected virtual in
ContentEditingServiceBase and override it in ElementEditingService to
check IsElement and AllowedInLibrary. This guards both create and update
paths (previously only create was guarded) and eliminates duplicate
ContentTypeNotFound handling.

Enable the previously-ignored
Cannot_Create_Element_Based_On_NonElement_ContentType test and add a new
test for the AllowedInLibrary check.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:01:34 +01:00
Laura NetoandGitHub d0acfa46bc Audit: Fix container update operations incorrectly logged as new (#21774)
Fix EntityTypeContainerService.UpdateAsync using wrong AuditType

UpdateAsync was logging AuditType.New instead of AuditType.Save,
causing container update operations to be recorded as creations
in the audit log.
2026-02-17 08:43:10 +01:00
Andy Butland 7a12f056e4 Merge branch 'main' into v18/dev 2026-02-17 07:33:01 +01:00
Andy ButlandandGitHub dbdafbdc19 Migrations: Re-trust untrusted foreign key and check constraints on SQL Server and fix bulk inserts to prevent recurrence (#21744)
* Be explicit about creating foreign key constrains with check (already the default).

* Add a migration to attempt to ensure that all constrains a trusted.

* Updated name of migration class.

* Ensure long timeout for migration.

* Update BulkInsertRecordsSqlServer to use SqlBulkCopyOptions.CheckConstraints and verify that no untrusted constraints remain afterward.

* Ensure NPoco InsertBulk uses SqlBulkCopyOptions.CheckConstraints by introducing UmbracoSqlServerDatabaseType (subclass of SqlServer2012DatabaseType) that overrides InsertBulk to pass SqlBulkCopyOptions.CheckConstraints.

* Also handle InsertBulkAsync.
2026-02-17 07:11:24 +01:00
Mads RasmussenandGitHub 3ef02bd3fa Tree: Provide UmbEntityContext from the tree item context base (#21770)
* Provide UmbEntityContext from tree item

* add tests to ensure entity context is provided
2026-02-16 19:37:04 +01:00
Andy ButlandandGitHub ba0d865ac9 Decimal Property Editor: Increase step size precision for configuration fields (closes #21759) (#21769)
Increase precision available to decimal data types.
2026-02-16 15:30:15 +01:00
Kenn JacobsenandGitHub 391e8a0867 Fix the integration tests project file structure (#21766) 2026-02-16 11:27:11 +00:00
0ca1a861e9 Elements: Add webhooks support (#21697)
* Add webhooks for elements

* Review: Removed unused payload type

* Use new object as empty payload

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-02-16 10:36:00 +01:00
dependabot[bot]andJacob Overgaard 541958b8c3 Bump qs
Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client directory: [qs](https://github.com/ljharb/qs).


Updates `qs` from 6.14.1 to 6.14.2
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-16 10:31:35 +01:00
Laura Neto e3135685da Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Core/Services/UserService.cs
2026-02-16 10:28:54 +01:00
9c1a810fc7 Permissions: Fix GetPermissionsAsync to resolve permissions from nearest ancestor (#21741)
* Fix GetPermissionsAsync to use path-based permission inheritance

GetPermissionsAsync was querying only explicit per-node permissions,
ignoring the ancestor-based inheritance model. Nodes without explicit
permissions would get group defaults instead of inheriting from their
nearest ancestor with explicit permissions. This caused tree filtering
to hide child nodes that should have been visible.

Replace per-node permission queries with GetPermissionsForPath which
walks the entity path to resolve inherited permissions correctly. Also
pass object types through to enable batched entity lookups.

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Optimise GetPermissionsAsync.

* Add benchmark test.

* Add benchmark test.

* Add integration tests for default and isolated permission resolution

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-16 09:57:34 +01:00
695807b32e Delivery API: Make the Delivery API "access" attributes public (closes #21677) (#21760)
* Make the Delivery API "access" attributes public

* Update src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiAccessAttribute.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiMediaAccessAttribute.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Also make the VersionedDeliveryApiRouteAttribute public

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-16 08:20:09 +01:00
dependabot[bot]andJacob Overgaard 30c6350643 Bump the npm_and_yarn group across 2 directories with 2 updates
Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client directory: [markdown-it](https://github.com/markdown-it/markdown-it).
Bumps the npm_and_yarn group with 2 updates in the /src/Umbraco.Web.UI.Login directory: [lodash](https://github.com/lodash/lodash) and [markdown-it](https://github.com/markdown-it/markdown-it).


Updates `markdown-it` from 14.1.0 to 14.1.1
- [Changelog](https://github.com/markdown-it/markdown-it/blob/master/CHANGELOG.md)
- [Commits](https://github.com/markdown-it/markdown-it/compare/14.1.0...14.1.1)

Updates `lodash` from 4.17.21 to 4.17.23
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

Updates `markdown-it` from 14.1.0 to 14.1.1
- [Changelog](https://github.com/markdown-it/markdown-it/blob/master/CHANGELOG.md)
- [Commits](https://github.com/markdown-it/markdown-it/compare/14.1.0...14.1.1)

---
updated-dependencies:
- dependency-name: markdown-it
  dependency-version: 14.1.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: markdown-it
  dependency-version: 14.1.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 21:53:21 +01:00
6f0fd8f6ec Elements: Add reference settings support (#21601)
* Elements: Add DisableDeleteWhenReferenced support and fix delete notifications

- Add DisableDeleteWhenReferenced check to ElementContainerService delete operations
- Fire ElementDeletedNotification and EntityContainerDeletedNotification per item during descendant deletion
- Fix potential infinite loop when items are skipped due to being referenced
- Simplify EmptyRecycleBinAsync to use DeleteDescendantsLocked directly
- Use path descending ordering for consistent deletion order (children before parents)
- Add test for descendant delete notifications

* Elements: Fix EmptyRecycleBin pagination with DisableDeleteWhenReferenced

When DisableDeleteWhenReferenced is enabled and some items are skipped,
the standard skip/take pagination breaks. This change:

- Adds SqlLessThan/SqlGreaterThan SQL expression extensions for string
  comparison in LINQ queries
- Uses path-based cursor pagination instead of skip/take
- Tracks protected paths to prevent deleting containers that have
  referenced descendants
- Adds ElementRecycleBin to UmbracoObjectTypes enum

* Tests: Add DisableUnpublishWhenReferenced tests for elements

Verify that DisableUnpublishWhenReferenced works correctly for elements
(inherited from ContentPublishingServiceBase):
- Cannot unpublish an element that is being referenced
- Can unpublish an element that is doing the referencing

* Elements: Remove redundant Trashed filter from DeleteDescendantsLocked

The Trashed filter was redundant because:
- EmptyRecycleBinAsync only operates on items under the recycle bin root
- DeleteFromRecycleBinAsync requires containers to be trashed, and all
  descendants are marked as trashed when moved to recycle bin

Removing the filter simplifies the query and handles edge cases better.

* Elements: Add proper ProblemDetails responses for publish/unpublish endpoints

Move ContentPublishingOperationStatusResult from DocumentControllerBase to
ContentControllerBase so it can be shared. Add ElementPublishingOperationStatusResult
to ElementControllerBase and update PublishElementController and
UnpublishElementController to return proper error responses instead of empty
BadRequest() when operations fail (e.g., when DisableUnpublishWhenReferenced is enabled).

* Refactor: Use abstract EntityName for content controller error messages

Replace hardcoded "document" terminology in shared ContentControllerBase
error messages with an abstract EntityName property, so each subclass
(document, element, media, member, etc.) provides context-appropriate
error messages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix: Check DisableUnpublishWhenReferenced when moving elements to recycle bin

ElementEditingService.MoveToRecycleBinAsync was missing the reference
check that ContentEditingService already performs for documents. This
allowed referenced elements to be moved to the recycle bin even when
DisableUnpublishWhenReferenced was enabled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Prevent moving container to recycle bin when descendants are referenced

Add server-side validation to ElementContainerService.MoveToRecycleBinAsync
that checks for referenced descendants when DisableUnpublishWhenReferenced
is enabled. Uses ITrackedReferencesService.GetPagedDescendantsInReferencesAsync
as an upfront check before any move processing begins.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 16:02:43 +01:00
785168cacd Persistence Models: DTO attributes fixes (#21670)
* quote table, column and alias names with SqlSyntaxProvider methods in raw sql

* refactoring private methods into new file as internal methods,
refactor new extensions into another file

* refactor GetAlias method

* Double check the change

* improve code health

* change new static classes into public static partial class NPocoSqlExtensions

* resolve some Copilot review suggestions

* revert Copilot suggestion because it decreases code health

* revert test

* compare in with LOWER, change two methods from private to protected in UmbracoDatabaseFactory

* revert Query.cs in this PR

* Refactor for code health and fixing raw sql

* divers small issues fixed

* refactor two methods to respect the DRY pricipal

* update IQuery interface

* clean up

* revert refactoring for CodeScene

* delete obsolete Test

* rename method

* remove new methods and updates, which are not relevat for this PR

* prepare for additional states in the future

* don't mix string building methods

* fix SQL injection danger

* fix test for reverted methods

* another SqlSyntax issue

* fix update

* fix reverted changes

* restore change for this PR

* restore change for this PR

* fix merge bug

* update formating

* extend ISqlSytax for database independent autoIkrement feature

* fix DTOs, extend ISqlSyntax

* fix tests

* revert

* updates

* diverse SqlSyntax and NPoco related updates for custom databse providers

* fix names

* fix PrimaryKey for multi columns

* Resolve the issues with SqlSyntaxProvider for SQLite. If executed correctly, a single test would reveal the problem.

* add another test

* revert changes which causes even more issues

* fix column const naming

* ensure column const names from v17.2

* add comment for change

* Update src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeTemplateDto.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* resolve review comments

* Make ReferenceMemberName consistent across all DTOs (use constants defined on the referenced DTO).

* Ensure [ExplicitColumns] attribute exists on all DTOs.

* Ensure we consistently use PrimaryKeyColumnName over PrimaryKeyName.

* Fix further inconsistency to use only TemplateNodeIdColumnName.

* Fixed trailing whitespace.

* Restored primary key constraint name on ContentVersionCleanupPolicyDto (it doesn't seem in scope of PR to remove this).

* Removed the confusing PrimaryKeyColumnName constants for multi-column primary key DTOs where the constant refers to only one of the key columns.

* ReferenceMemberName needs to be a C# property name, so it's safer to use nameof.

* Comment fix.

* Amended accessibility modifiers.

* Fixed/tidied comments.

* Fixed references from UserGroupDto.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-13 11:42:36 +00:00
MoleandGitHub 8ace1e0e94 Persistence models: Fix incorrect webhook DTO (#21736)
Fix incorrect webhook dto
2026-02-13 11:48:48 +01:00
Jacob OvergaardandGitHub 4ce56e4bc9 Entity Actions: Adds a descriptive title to the first action so you know what it does (#21739)
* fix: adds a title to the first entity action in the entity actions bundle, otherwise you do not know what it does, unless the icon is very descriptive

* calculate the label once

* concatenate data-mark string better
2026-02-13 08:51:24 +01:00
Laura NetoandGitHub ebcb996431 Elements: Fix delete blocked by trash-tracking relation (#21725)
Fix element delete blocked by trash-tracking relation

ElementEditingService was missing the RelateParentOnDeleteAlias
override, so the "relate parent on delete" relation created when
trashing was not excluded from the reference check. This caused
"Cannot delete a referenced content item" when
DisableDeleteWhenReferenced was enabled, even for unreferenced
elements.
2026-02-13 07:30:28 +01:00
8cbf68223a Global Elements: UI refinements, element picker and constants tidy-up (#21737)
* improvement(elements): general UI updates, element picker rework, and constants tidy-up

* fix(elements): forward min/max messages through umb-input-element and minor cleanups

Add minMessage/maxMessage properties to UmbInputElementElement so validation
messages are properly forwarded to the inner umb-input-entity-data component.
Also fix JSDoc grammar, variable naming, and comment tidying.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(elements): sync value/selection and register inner form control in umb-input-element

Add getter/setter overrides for value and selection that keep them in sync
(matching umb-input-content pattern), and register the inner umb-input-entity-data
via addFormControlElement() in firstUpdated() so validation propagates correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(elements): use correct element ID in referenced-by mock handler

Change sentinel ID from 'all-property-editors-document-id' to 'simple-element-id'
to match the actual element mock fixture IDs in element.data.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(elements): add unit test for umb-input-element

Add instantiation and conditional a11y audit tests following the
umb-input-document.test.ts pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:49:56 +00:00
39f19bf3ab Global Elements: Rollback UI (#21712)
* feat(elements): add element rollback repository, modal, and audit log

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Exported rollback constants

* Update src/Umbraco.Web.UI.Client/src/packages/elements/rollback/modal/rollback-modal.element.ts

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-02-12 17:08:08 +00:00
Nhu DinhandGitHub 0b6507a02e E2E: QA Updated acceptance tests for adding block element to match the UI changes (#21679) 2026-02-12 23:29:11 +07:00
Niels Lyngsø e8c0dd897b Merge branch 'main' into v18/dev 2026-02-12 16:27:28 +01:00
66fbade194 Global Elements: Workspace Validation UI (#21711)
* feat(elements): add element workspace validation repository

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Global Elements: Address Copilot review feedback on validation PR

Fix JSDoc comments on validation repository/data-source to accurately
describe validation behavior instead of persistence. Use barrel import
for validation repository and remove leftover commented-out code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Global Elements: Remove redundant guard clauses in validation data source

Remove TypeScript-redundant checks in validateCreate to reduce
cyclomatic complexity below the CodeScene threshold of 9.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-02-12 15:12:23 +01:00
ae2761f204 Global Elements: Reference Tracking UI (#21710)
* feat(elements): add element reference tracking repository

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fixed linting errors

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 15:02:20 +01:00
a374042e89 Textbox/area: Add character countdown message (closes #19505) (#21722)
* Show character count and instant exceed validation.

* Show character count for textarea editor.

* Add character-count utility and use in editors.

* Rename char count state, add tests, fix imports.

* Update textbox character messages in locales.

* Apply suggestions from code review

* Align textarea and textbox in use of #getMaxLengthMessage private helper function.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-12 13:27:27 +00:00
bc0110079c Package Manifest: Enable cache buster token replacement for extensions (closes #16893) (#21709)
* fix(manifest): replace %CACHE_BUSTER% token in extension paths served by manifest API

Move cache buster replacement to the presentation layer (manifest controllers)
instead of the infrastructure service. The importmap replacement stays in
HtmlHelperBackOfficeExtensions where it was already handled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Ordered usings.

* Add unit test for cache buster token replacement.

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Fix ambiguous controller constructors.

* Make ReplaceCacheBusterTokens void since it mutates in-place.

* Defensively code against special characters in the cache buster hash.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-12 11:35:58 +00:00
394de9e2d0 Imaging: Intelligent format detection for thumbnail generation (#21570)
* Imaging: Add format parameter to thumbnail component with webp default

Adds a format parameter to the imaging resize API endpoint and the
umb-imaging-thumbnail component. The component defaults to 'webp' format
for optimal browser support and smaller file sizes.

This ensures that non-image file types (like PDFs) that have custom image
providers can render thumbnails correctly by explicitly requesting an
output format instead of relying on the original file extension.

Changes:
- Add format query parameter to ResizeImagingController
- Pass format through IReziseImageUrlFactory to ImageUrlGenerationOptions
- Add format property to UmbImagingResizeModel TypeScript type
- Add format property to umb-imaging-thumbnail element (default: 'webp')

https://claude.ai/code/session_01GP7N2iTashrG1cBdYVSW97

* Imaging: Include format in cache key generation

Fix cache key to include the format parameter so that different format
requests with identical dimensions are cached separately.

https://claude.ai/code/session_01GP7N2iTashrG1cBdYVSW97

* Imaging: Refactor to use ImageResizeOptions record

Introduces ImageResizeOptions record to encapsulate resize parameters,
addressing CodeScene's "Excess Number of Function Arguments" warning.

Changes:
- Add ImageResizeOptions record with Height, Width, Mode, Format properties
- Add new CreateUrlSets overload accepting ImageResizeOptions
- Mark old CreateUrlSets overload as obsolete (removal in v19)
- Update controller to use new options pattern

https://claude.ai/code/session_01GP7N2iTashrG1cBdYVSW97

* Imaging: Add explicit obsolete method to satisfy API compatibility

The API compatibility checker requires the method to exist explicitly
in the implementation, not just via default interface method.

Co-Authored-By: Claude <noreply@anthropic.com>

* Imaging: Add unit tests for imaging store format parameter

Tests verify that:
- Different formats are cached separately (webp vs png)
- Crops with and without format are cached separately
- Cache operations work correctly with format parameter

Co-Authored-By: Claude <noreply@anthropic.com>

* Add API compatibility suppression for resize imaging endpoint

Suppress CP0002 for adding optional 'format' parameter to the resize
imaging controller endpoint. The HTTP API remains backward compatible
as existing clients simply won't send the new parameter.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix API compatibility for IReziseImageUrlFactory

Restructure interface to maintain binary compatibility:
- Keep original 4-parameter method as required (marked obsolete)
- Add new ImageResizeOptions overload with default implementation
- Factory overrides new method to properly handle format parameter

This allows existing implementations to continue working while
new code uses the ImageResizeOptions overload with format support.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(api): regenerate API compatibility suppression file

Regenerated the CompatibilitySuppressions.xml file with proper metadata
to suppress the breaking change detection for the optional format parameter
added to ResizeImagingController.Urls method. This change is backward
compatible at the HTTP API level.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat(imaging): automatic format conversion for non-image files

Move format conversion logic from frontend to backend IImageUrlGenerator
implementations to handle format defaults intelligently based on source
file types.

Why Backend Should Handle This:
1. **Source-aware decisions**: Backend has access to source file extension
   and can determine if it's a true image (jpg, png) or processable
   non-image (pdf with plugin)

2. **Consistent behavior**: All consumers (backoffice, APIs, custom code)
   get consistent format handling without duplicating logic

3. **Plugin compatibility**: When ImageSharp plugins add support for new
   file types (e.g., PDF thumbnails), the system automatically converts
   them to web-compatible image formats

4. **User override preserved**: Explicit format parameter still works as
   an override, giving users control when needed

Changes:
- Add Format property to ImageUrlGenerationOptions for explicit format requests
- ImageSharp implementations auto-detect non-image files and default to WebP
- ReziseImageUrlFactory passes format directly instead of via FurtherOptions
- Frontend imaging-thumbnail component removes hardcoded format='webp' default
- Backend now handles: format override > auto-detect non-images > keep original

Example Scenarios:
- JPEG → No format added (keeps JPEG)
- PNG → No format added (keeps PNG)
- PDF (with plugin) → Auto-adds format=webp
- Any file + explicit format param → Uses specified format

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(imaging): improve robustness and code quality

Address code review feedback with three improvements:

1. Add URI parsing error handling to prevent UriFormatException crashes
   when malformed URLs are passed to RequiresFormatConversion()

2. Extract magic string array to class-level constant (TrueImageFormats)
   to eliminate duplication and provide single source of truth

3. Remove inconsistent default interface implementation that didn't pass
   format parameter, forcing concrete implementations to handle it properly

All changes maintain backward compatibility and improve code safety.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor(imaging): move format determination to factory layer

Refactors format conversion logic from ImageSharp implementations to the factory layer for better separation of concerns and maintainability.

Changes:
- Add ContentImagingSettings.TrueImageFormats configuration (native image formats)
- Move format determination logic to ReziseImageUrlFactory.DetermineOutputFormat()
- Simplify ImageSharp v1 & v2 generators (remove duplicate RequiresFormatConversion())
- Add backward-compatible obsolete constructor to ReziseImageUrlFactory
- Add 50 comprehensive unit tests for format determination and configuration

Benefits:
- Single Responsibility: ImageSharp generators only generate URLs, don't make business decisions
- DRY: Eliminated 70+ lines of duplicated code between ImageSharp packages
- Configurable: TrueImageFormats setting allows customization
- Testable: Format logic tested independently of ImageSharp

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor(imaging): repurpose ImageFileTypes for native format determination

Repurposes the existing unused ContentImagingSettings.ImageFileTypes setting instead of adding a new TrueImageFormats property. This provides better configuration control and eliminates the need for a new setting.

Changes:
- Repurpose ContentImagingSettings.ImageFileTypes (was unused, now active)
- Update ReziseImageUrlFactory to use ImageFileTypes for format determination
- Update TemporaryFileConfigurationPresentationFactory to use config instead of IImageUrlGenerator
- Add comprehensive XML documentation explaining usage in factory layer and backoffice UI
- Update all tests to reference ImageFileTypes

Benefits:
- No new configuration property needed (reuses existing setting)
- Frontend gets configurable format list instead of dynamic ImageSharp formats
- Better separation of concerns (config determines behavior, not infrastructure)
- Clearer documentation of where and how the setting is used

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* test(core): remove duplicate test methods in ContentImagingSettingsTests

Removed duplicate test methods that were causing compilation errors:
- ImageFileTypes_DefaultValue_ContainsExpectedFormats (duplicate)
- ImageFileTypes_DefaultValue_MatchesStaticConstant (duplicate)
- ImageFileTypes_CanBeConfigured_WithCustomFormats (duplicate with incorrect test data)
- Contradicting assertion in StaticConstants_HaveExpectedValues

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(api): suppress CP0006 for IReziseImageUrlFactory.CreateUrlSets overload

Added API compatibility suppression for the new CreateUrlSets overload that
accepts ImageResizeOptions parameter. This change is backward compatible as the
concrete implementation already has both methods and the old method is marked
obsolete to guide users.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fixes merge conflict

* formatting

* fix(api): suppress CP0002 for TemporaryFileConfigurationPresentationFactory constructor change

Added suppression for constructor signature change where IImageUrlGenerator
parameter was replaced with IOptionsSnapshot<ContentImagingSettings> to get
ImageFileTypes directly from configuration instead of from the image URL
generator.

This change is part of the WebP thumbnail feature and aligns with getting
native format information from ContentImagingSettings configuration.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(api): maintain backward compatibility for TemporaryFileConfigurationPresentationFactory constructor

Instead of suppressing the CP0002 error, added back the old constructor marked
as [Obsolete] that chains to the new one. The old constructor:
- Accepts the original parameters (ContentSettings, RuntimeSettings, IImageUrlGenerator)
- Ignores the IImageUrlGenerator parameter (kept only for backward compatibility)
- Uses StaticServiceProvider to get ContentImagingSettings
- Chains to the new constructor

This maintains full backward compatibility while migrating to the new approach
where ImageFileTypes comes directly from ContentImagingSettings configuration.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* test(core): update StaticConstants_HaveExpectedValues test to match actual constant value

The test was checking for format order 'jpg,jpeg,png,gif,webp,bmp,tif,tiff' but
the actual constant StaticImageFileTypes is 'jpeg,jpg,gif,bmp,png,tiff,tif,webp'.
Updated the test to match the actual constant value.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(api): resolve constructor ambiguity in TemporaryFileConfigurationPresentationFactory

Add [ActivatorUtilitiesConstructor] attribute to the new constructor to explicitly
indicate which constructor the DI container should use when both constructors have
the same number of parameters.

This fixes the "ambiguous constructors" error that was preventing the OpenAPI
contract test from running.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: adds parameter even though it is unused to help the DI system figure out which constructor to use

* test(api): update ReziseImageUrlFactory test to reflect corrected query string handling

The implementation was fixed to correctly handle URLs with query strings by
stripping the query string before extracting the file extension. Updated the
test expectations to verify that PDFs with query strings are now processed
correctly and converted to WebP format, rather than returning empty results.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore: adds double obsolete constructor to stay persistent and be able to use only new constructor with same amount of arguments

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Address remaining PR #21570 review comments

- Add GetFileExtension() to UriExtensions for reusable URI extension extraction
- Simplify ReziseImageUrlFactory to use GetFileExtension() instead of manual parsing
- Add default implementation to IReziseImageUrlFactory to avoid CP0006 breaking change
- Remove CP0006 suppression from CompatibilitySuppressions.xml
- Fix Obsolete message format and remove unnecessary [ActivatorUtilitiesConstructor]
- Add TODO for ReziseImageUrlFactory typo rename
- Remove stale ObsoleteOverload test and low-value ContentImagingSettingsTests
- Add unit tests for UriExtensions.GetFileExtension()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Avoid unnecessary second call to GetFileExtension().

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-12 11:21:06 +00:00
6a4b28b78a Management API: Optimize collection view performance by eliminating N+1 patterns (#21684)
* Added further integration test to verify list view permission checks.

* Replace per item GetPermissionsForPath calls with a single batch GetPermissions query across all unique path node ids.

* Added unit test verifying DocumentCollectionPresentationFactory and fixed constructors.

* Replace per-item IsProtected calls with a single batched GetAll query and in-memory path matching.
Compute shared ancestor path keys once for collection siblings instead of per item.

* Eliminate redundant GUID to int conversions in HasScheduleFlagProvider.

* Batch user profile resolution in collection view mapping.

* Addressed issues from code review.

* DRY up GetOwenerName and GetCreatorName in CommonMapper.

* Apply suggestions from code review

Co-authored-by: Mole <nikolajlauridsen@protonmail.ch>

* Apply feedback from code review.

---------

Co-authored-by: Mole <nikolajlauridsen@protonmail.ch>
2026-02-12 10:22:39 +00:00
Andy Butland a49981b6c5 Merge branch 'main' into v18/dev 2026-02-12 06:50:15 +01:00
Andy ButlandandGitHub 74858e2c44 Repositories: Fix GetAllContentTypeIds query on content type to generate correct SQL (#21612)
* Fixes the failing repository method ContentTypeRepository.GetAllContentTypeIds.

* Revert syntax change.
2026-02-12 06:40:12 +01:00
Niels Lyngsø 0b2516050f add data-marks 2026-02-11 21:44:34 +01:00
Lee KelleherandGitHub d21d1453f5 Global Elements: Exports all constants for @umbraco-cms/backoffice/element (#21727) 2026-02-11 17:52:40 +01:00
a6c363001c Chore: Hide generated files from GitHub PR diffs (#21713)
Mark hey-api generated client code and OpenApi.json as linguist-generated
so they are collapsed by default in GitHub diffs and excluded from
language statistics.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:36:54 +00:00
Mads Rasmussen 4286daa4b5 Lazy-init picker modal route 2026-02-11 13:12:51 +01:00
Niels Lyngsø 11e19466f8 Merge branch 'main' into v18/dev 2026-02-11 12:52:14 +01:00
Niels Lyngsø e194776103 Merge branch 'release/17.2'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts
#	version.json
2026-02-11 12:51:59 +01:00
551865b79e Entity Data Picker: Register non-editor manifests statically (#21721)
fix(web): register entity data picker non-editor manifests statically

The entity data picker's picker infrastructure manifests (collection menu,
item, search, tree) were only registered dynamically via the entry point,
meaning they were unavailable until a picker data source was detected.
Split the registration so these manifests are registered statically through
the main property-editors manifest tree, while only property editor manifests
remain dynamically registered.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 11:45:24 +00:00
028e9affd9 Long Running Operations: Increase type column length and handle rebuilds of Examine indexes with long names (closes #21666) (#21715)
* Update length of type column in LongRunningOperation

* Adding truncation

* Update src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Used constants.
Handled case where long strings with the same first 200 characters could end up clashing (very unlikely, but we can be defensive).
Introduced a TruncateWithUniqueHash extension method to support this.

* Reverted comment removal.

* Rename migration class.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-11 11:36:57 +00:00
b1ef0153f3 Block Workspace: Inline Editing Workspace to awaits all Content Type compositions before setting initial active tab (#21719)
* fix contentTypeLoaded reaction in Block Workspace without a router

* Update src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-content-no-router.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* revert check with todo comment

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-11 11:25:45 +00:00
114dc9bc91 API Docs: Fix and optimize DocFX API documentation pipeline (#21707)
* Use dotnet tool instead

* Uses pipeline build artifacts to reduce compilation time

* Fixed name

* Remove --noRestore

* Move DocFX metadata generation to Build stage

* Updated to use dlls

* Docs: Fix DocFX CSS reference for newer DocFX version

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Added conditions for generating DocFX metadata

* use glob pattern for DLLs

* Move DocFX to Build_Docs stage with separate DLLs artifac

* Fixes based on comments

* Undo commented out Upload C# Docs job

* Removed Build_Docs from Nuget Release so our docs isnt blocking

* Added dependsOn so Upload_API_Docs is only done when Build_Docs are finished

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 10:00:07 +01:00
Niels LyngsøGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>nielslyngsoe
a1bcabf44e (fixes #21178) (#21672)
* Initial plan

* Add tab badges for validation errors in block workspace

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Build successful - frontend changes compiled

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* remove double naming

* remove double naming in no router block workspace

* fixing code

* debugger

* binding view contexts

* inline mode binding

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>
2026-02-10 14:29:38 +00:00
Laura Neto d51de53804 chore(api): regenerate OpenApi.json and backoffice client SDK
The OpenAPI definition and backoffice TypeScript client were out of
sync with recent Management API changes already on v18/dev. Regenerated
to bring them up to date.
2026-02-10 15:25:21 +01:00
Andy ButlandandGitHub f3595a8ae6 User Management: Avoid discard changes dialog after enabling/disabling a user (closes #19019) (#21702)
Avoid discard changes modal when enabling or disabling a user.
2026-02-10 14:17:23 +00:00
Niels LyngsøandGitHub bfee99c5b0 Block Workspace: Tabs navigation, Cherry-pick from #21672 (#21693)
* cherry-pick from #21672

* cherry pick tab rendering to handle one more case

* move the root route down for it to stay an empty path.

* Revert empty root path commit

* fullPath for root includes 'root'

* revert claude settings commit

* refactor accordingly to feedback
2026-02-10 14:17:14 +00:00
Andy Butland ed963b2dbb Bumped version to 17.2.0-rc2. 2026-02-10 15:16:52 +01:00
Niels Lyngsø fc43d5316f Merge branch 'release/17.2' 2026-02-10 14:42:35 +01:00
Niels LyngsøandGitHub 79dfe76286 Block Workspace: renme root-tab to 'generic' (#21699)
* renme to generic

* only use label
2026-02-10 13:31:01 +00:00
Laura Neto 8b5448adcd Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Core/Constants-Security.cs
#	src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs
#	src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs
#	src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs
#	src/Umbraco.PublishedCache.HybridCache/PublishedContent.cs
#	src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts
2026-02-10 14:02:51 +01:00
Andy ButlandandGitHub ecb4ecdc1a Developer Experience: Clarify obsoletion warning messages (#21695)
* Updates all obsoletion messages to use a softer expression of intent rather than stating explicit removal in a particular version.

* Code review feedback.

* Updates from code review.
2026-02-10 11:47:49 +00:00
Laura NetoandGitHub 78d6229b8e Task: Regenerate OpenAPI definition and backoffice client SDK (#21694)
chore(api): regenerate OpenApi.json and backoffice client SDK

The OpenAPI definition and backoffice TypeScript client were out of
sync with recent Management API changes already on main. Regenerated
to bring them up to date.
2026-02-10 10:01:46 +00:00
cf70d7ff13 Global Elements: Refactor content and element repositories into a common base (#21637)
* Begin implementation of repo base

* Move internal mapping - part 1

* Move internal mapping - part 2

* Move versioning, persistence, GUID sub repo and utilities to base

* Fix wrong assumption in cache tests

* Move content repo + recycle bin to base

* Move schedule to base

* Move common delete clauses to base

* Move DTO mapping to base

* Fix a few of the pending TODOs for elements

* Abstract OnUowRefreshedEntity away to concrete implementations

* Handle template editing in a less hardcoded way

* Restore DTO visibility for elements

* Update src/Umbraco.Core/Cache/CacheKeys.cs

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

* Update src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublishableContentRepositoryBase.cs

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

* Update src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublishableContentRepositoryBase.cs

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

* Update cache key (review comment)

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
2026-02-10 09:54:38 +01:00
e035c8541a Developer Experience: Clarify nullability for BackOfficeAuthenticationBuilder.SchemeForBackOffice (closes #21689) (#21690)
* #21689: signature fix

* #21689: namespace fix

* Update src/Umbraco.Cms.Api.Management/Security/BackOfficeAuthenticationBuilder.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-10 09:47:45 +01:00
b5ec111351 Docs: Add breaking changes avoidance policy to CLAUDE.md (#21683)
* Updated Claude memory files with details on how to handle binary breaking changes.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-10 09:20:37 +01:00
6db77ec155 Security settings: Add UserPassword and MemberPassword properties to SecuritySettings for appsettings.json IntelliSense (#21681)
* Fix suggestion appsettings issue

* Add todo comment to remove UserPasswordConfigurationSettings and MemberPasswordConfigurationSettings

* Apply suggestions from code review

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-10 08:00:53 +00:00
Niels LyngsøandGitHub eea17292c8 Extension Slot: JS Docs update (#21645)
* remove not existing script from Claude settings

* append JS docs for extension-slot and extension-with-api-slot
2026-02-09 15:07:03 +00:00
Niels LyngsøandGitHub 21a17a4d74 Block Grid Editor: improved extension initialization for Inline Mode Blocks (#21661)
improve extension initialization life cycle
2026-02-09 15:54:14 +01:00
c4d4c17d63 Enable usage of umb-input-entity-data element without registering a propertyEditorDataSource. (#21686)
* resolve Property Editor Data Source apis in the Property Editor UI

* load input-entity-data globally

* Update src/Umbraco.Web.UI.Client/src/packages/property-editors/entity-data-picker/property-editor/entity-data-picker-property-editor-ui.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Create/teardown data-source API on alias change

* Initialize _dataSourceConfig inside extractor

* Allow clearing entity data picker data source

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-09 15:50:34 +01:00
f0dc972bf2 Elements: Add restore from recycle bin functionality (#21556)
* Elements: Add restore from recycle bin functionality

- Add RestoreAsync to IElementEditingService and ElementEditingService
- Add RestoreAsync to IElementContainerService and ElementContainerService
- Add RestoreElementRecycleBinController and RestoreElementFolderRecycleBinController API endpoints
- Add TryGetContainedObjectType to EntityContainer for graceful handling of non-container types
- Update EntityContainerRepository to return null instead of throwing for non-container entities
- Add comprehensive integration tests for element and container restore operations

* Refactor: Remove entity return from Move/Restore/MoveToRecycleBin methods

Simplify the return types of IElementEditingService and IElementContainerService
move operations to return only the operation status instead of the entity.

These operations don't meaningfully change entity data (just location/state),
and no consumers were using the returned entities. Callers can use GetAsync
if they need the updated entity afterward.

* Fix: Capture original path before move for restore relation cleanup

The MoveEventInfo.OriginalPath was incorrectly set to the element's path
after the move, causing DeleteOriginalParentRelationsOnRestore to fail
because the path no longer contained the recycle bin path prefix.

* Tiny little formatting

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-02-09 13:39:25 +00:00
Niels LyngsøandGitHub 49be5b6e9b Block Grid Editor: adjust styling of default Grid Block views (Fixes #16375) (#21685)
adjust styling of default Grid Block views
2026-02-09 13:19:08 +00:00
Andy Butland 81276fc048 Adds endpoint summaries and descriptions to new controllers introduced since 17. 2026-02-09 13:04:54 +01:00
Andy Butland 58f300a20d Merge branch 'main' into v18/dev 2026-02-09 12:36:23 +01:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>AndyButlandOwain WilliamsAndy ButlandCopilot
22f7cefcdf Add endpoint descriptions to all Management API controllers (#20690)
* Initial plan

* Add EndpointSummary and EndpointDescription to all Management API endpoints

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Add missing using directive for EndpointSummary attributes

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Fix English compound words and add missing Webhook endpoint descriptions

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Add endpoint descriptions to remaining 359 Management API endpoints

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Add final endpoint descriptions - 434 of 441 endpoints now documented

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Fix concatenated words, duplicate attributes, and missing using statements

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Fix using statement alphabetical order and remove all duplicate attributes

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Revert "Fix using statement alphabetical order and remove all duplicate attributes"

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Fix using statement order and remove duplicate attributes

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Add endpoint descriptions to final 7 Management API endpoints

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Simplify endpoint descriptions - remove redundant phrases and fix compound words

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Revert Create and Update controller description simplifications

Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>

* Updated to Controllers/Document controllers (#20917)

* [ADD] Cultures Summary and Description

* tidy up from previous merge issue

* update wording on notifications controller

* UpdateDomainsController wording update

* Update the UpdateNotificationsController description / summary

* UpdatePublicAccessDocumentController update

* naming Document Blueprint as referenced in the Docs

* renaming Document Blueprint to match Group Name

* Document Blueprint updates

* Document Type Folder controllers

* Document Type Item endpoints

* Aligned casing.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix compound words, incorrect pluralisiation and other endpoint documentation issues.

* Add descriptions to controllers missing them.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: AndyButland <1993459+AndyButland@users.noreply.github.com>
Co-authored-by: Owain Williams <owaingdwilliams@gmail.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-09 12:35:40 +01:00
56b657d389 Content Type Properties: make content type property responsive (#21559)
make content type property responsive

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-02-09 09:45:06 +00:00
899beaa9d1 Initial update to a couple of Management API endpoints (#20549)
* Update README.md with information about the forum

Making a small change to the Readme to signpost the Forum now that it's the place to go for help/questions

* [TASK] Initial update of some Management API endpoints

* Update src/Umbraco.Cms.Api.Management/Controllers/Culture/AllCultureController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/UpdatePreventCleanupDocumentVersionController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/ByKeyDocumentVersionController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/AllDocumentVersionController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* [UPDATE] Small grammer update

* Update src/Umbraco.Cms.Api.Management/Controllers/Culture/AllCultureController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/Culture/AllCultureController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/AllDocumentVersionController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/AllDocumentVersionController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/ByKeyDocumentVersionController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/ByKeyDocumentVersionController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/RollbackDocumentVersionController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/RollbackDocumentVersionController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/UpdatePreventCleanupDocumentVersionController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DocumentVersion/UpdatePreventCleanupDocumentVersionController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* [WIP] Data Types

* [WIP] Update ByKey and Configuration DataTypes

* [AMEND] Add additional Summary and Descritpion to API endpoints on DataTypes

* [AMEND] Filter / Folder / Item / References / Tree API update

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/ConfigurationDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/CopyDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/CopyDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/DeleteDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/RootDataTypeTreeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/SiblingsDataTypeTreeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/SiblingsDataTypeTreeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/UpdateDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/UpdateDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/DeleteDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Filter/FilterDataTypeFilterController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Folder/ByKeyDataTypeFolderController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/ChildrenDataTypeTreeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Folder/ByKeyDataTypeFolderController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Folder/DeleteDataTypeFolderController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Folder/UpdateDataTypeFolderController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Folder/DeleteDataTypeFolderController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/ChildrenDataTypeTreeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Folder/UpdateDataTypeFolderController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Folder/CreateDataTypeFolderController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Item/ItemDatatypeItemController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Item/ItemDatatypeItemController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/AncestorsDataTypeTreeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Item/SearchDataTypeItemController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/MoveDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/MoveDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/References/ReferencedByDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/AncestorsDataTypeTreeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/References/ReferencedByDataTypeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/RootDataTypeTreeController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Owain Williams <ow@initials.co.uk>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-09 09:39:45 +01:00
4070158f8c Preset property value: acceptance test (#21498)
* Add tests for property presest value

* save method'

* update accepntance test

* ad timeout to preset value test

* Updated yaml file to copy all .cs files but still keep folder structure

* remove timeout from preset value test

* adding time wait to tests

* adding more timeout

* Adding slow test

* update test

* Format code

* Format code and add more afterEach step to clean language

* Remove test.slow() as it is unnecessary

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Nhu Dinh <hnd@umbraco.dk>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2026-02-09 08:09:10 +00:00
f5f6ee9bb3 Tiptap RTE: Add clipboard copy/paste support for RTE blocks (#21604)
* Localize "Copy to clipboard" button label

in other Block editor components.

* Adds "Copy to clipboard" action to RTE Block component

* Check if Clipboard Property Context is available

If not, don't show the action button.

* Register "Clipboard Property Context" for Tiptap RTE

we can't make this generic for all RTEs,
since it is bound to the property-editor UI alias.

* Implemented RTE Block's `copyToClipboard()` method

* Added Clipboard Property Value Translators

for Tiptap RTE Blocks.

* Block RTE: fix clipboard paste data structure mismatch

Change paste translator to output UmbPropertyEditorRteValueType (with
markup and blocks) instead of UmbBlockRteValueModel (flat structure).
This ensures the cloner receives the correct type and can properly
regenerate content keys.

Also optimize the cloner to skip DOM parsing when markup is empty,
which is always the case for clipboard paste operations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* TipTap: debounce block updates to prevent race condition

Add debounceTime to the contents observable to batch rapid emissions
when pasting multiple blocks from clipboard. This prevents the
#updateBlocks method from being called multiple times in quick
succession.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Block RTE: address code review feedback

- Add missing await on insert() and insertFromRtePropertyValues()
- Remove redundant optional chaining on blockContentTypes.every()

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-09 07:09:31 +00:00
Niels LyngsøandGitHub 145f054c2e Block Editor: UX Flow when creating one block / inline editing (#20836)
fix create ux-flow
2026-02-07 09:34:14 +01:00
023e00a975 21599: Removed the icon from redirect URL dashboard as per request in… (#21665)
21599: Removed the icon from redirect URL dashboard as per request in the issue discussion

Co-authored-by: Pasang Tamang <45009265+pasangtamang@users.noreply.github.com>
2026-02-06 19:19:03 +01:00
Niels LyngsøandGitHub 89ff306db4 Block Editors: Sync Validation Messages when in Inline Mode (Fixes #21518) (#21669)
* setup auto report for blocks validation in inline mode

* Single + grid implementation
2026-02-06 18:56:57 +01:00
32dbaf5f57 Collection: Add description support to default collection item card and ref elements (#21654)
* Add optional description to collection items

* Add optional description support to default item ref

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-02-06 17:09:35 +00:00
Mads RasmussenandGitHub 9892b35373 Collection: Fix undefined take in collection filter and hide pagination when all items are shown (#21662)
* Hide pagination when all items are shown

* Add a fallback page size
2026-02-06 17:34:21 +01:00
Mads RasmussenandGitHub bc53a73039 Extension Insights: Fix collection by avoiding shallow copy of manifests (#21660)
* fix problem with shallow copy because of js module in object

* nest manifest data
2026-02-06 17:32:27 +01:00
Nicklas KramerandGitHub 3527c01a70 Media Item Search: Fixing missing attribute for constructor (#21659)
Adding missing attribute to constructor
2026-02-06 12:19:28 +01:00
Niels Lyngsø f530772b80 Merge branch 'main' into v18/dev 2026-02-05 12:49:26 +01:00
087cc8db51 Backoffice NPM: use looser peerDependencies version ranges for plugin compatibility (#21644)
* feat(backoffice): use looser version ranges for peerDependencies

Convert hoisted dependencies to peerDependencies with more permissive version
ranges that allow plugin developers to use different versions without npm conflicts.

Version range strategy:
- Pre-release (0.x.y): >=X.Y.Z <1.0.0
  Example: @hey-api/openapi-ts 0.85.0 → >=0.85.0 <1.0.0
  Allows plugins to use 0.85.0, 0.91.1, 0.99.99 without conflicts

- Stable (major.x.y where major ≥1): major.x.x
  Example: lit ^3.3.1 → 3.x.x
  Allows any patch/minor within the major version

This allows plugin developers to:
- Use @hey-api/openapi-ts 0.91.1 while backoffice uses 0.85.0
- Install compatible deduplicated versions when available
- Override versions when needed for their specific use case

Types remain available from peerDependencies (automatically installed by npm 7+).
When @hey-api reaches 1.0.0, the range will automatically become ^1.0.0.

https://claude.ai/code/session_01CBpcwXYZjzexKkM9Cf57Kb

* refactor(backoffice): use semver package for version parsing in cleanse script

Replace regex-based version parsing with the semver package used by npm itself.
This ensures version parsing is consistent with npm's own semver handling and is
more robust for edge cases.

Also update the version range logic to be more explicit and correct:
- Pre-release (0.x.y): >=X.Y.Z <1.0.0
- Stable (1+.x.y): >=X.Y.Z <NEXT_MAJOR.0.0

This ensures plugin developers use at least the tested version and prevents
accidental downgrades to incompatible minor versions.

https://claude.ai/code/session_01CBpcwXYZjzexKkM9Cf57Kb

* chore: formats file

* chore: lockfile

* fix(backoffice): use semver.minVersion to parse version ranges

Fix parsing of version ranges like ^0.85.0 by using semver.minVersion() instead
of semver.parse(). The parse() function only handles exact versions, while
minVersion() extracts the minimum version from a range.

Example transformations:
- ^0.85.0 → 0.85.0 → >=0.85.0 <1.0.0
- ^3.3.1 → 3.3.1 → >=3.3.1 <4.0.0

https://claude.ai/code/session_01CBpcwXYZjzexKkM9Cf57Kb

* refactor(backoffice): keep caret ranges for stable package versions

Optimize the version range conversion logic:

- Stable versions (major ≥ 1) with caret (e.g., ^3.3.1): Keep as-is
  The caret already implements the desired range: >=3.3.1 <4.0.0

- Pre-release versions (0.x.y): Convert to explicit range
  ^0.85.0 → >=0.85.0 <1.0.0 (caret only allows 0.85.z, not 0.91.z)

- Exact versions (e.g., 3.16.0): Convert to range
  3.16.0 → >=3.16.0 <4.0.0

This simplifies the published package.json while maintaining the same semantics
and is more explicit about the intent.

Examples of published peerDependencies:
- lit: ^3.3.1 (unchanged, already has correct range)
- rxjs: ^7.8.2 (unchanged)
- @hey-api/openapi-ts: >=0.85.0 <1.0.0 (converted from ^0.85.0)
- @tiptap/core: >=3.16.0 <4.0.0 (converted from 3.16.0)

https://claude.ai/code/session_01CBpcwXYZjzexKkM9Cf57Kb

* refactor(backoffice): use caret for stable exact versions

Simplify stable exact versions (e.g., 3.16.0) by adding a caret prefix (^3.16.0)
instead of explicit range (>=3.16.0 <4.0.0). Both are semantically identical for
stable versions but caret is more concise and conventional.

Updated version range logic:
- Stable with caret (^3.3.1): Keep as-is
- Pre-release with caret (^0.85.0): Convert to >=0.85.0 <1.0.0
- Stable exact version (3.16.0): Convert to ^3.16.0

Examples of published peerDependencies:
- lit: ^3.3.1
- rxjs: ^7.8.2
- @hey-api/openapi-ts: >=0.85.0 <1.0.0
- @tiptap/core: ^3.16.0 (now with caret)

https://claude.ai/code/session_01CBpcwXYZjzexKkM9Cf57Kb

* refactor(backoffice): ensure all pre-release versions get explicit range

Reorganize version conversion logic for clarity:

1. All pre-release (0.x.y) versions → explicit range: >=X.Y.Z <1.0.0
   - Examples: ^0.85.0 → >=0.85.0 <1.0.0, 0.85.0 → >=0.85.0 <1.0.0

2. Stable versions with caret (^3.3.1) → keep as-is

3. Stable versions exact (3.16.0) → add caret: ^3.16.0

This ensures pre-release version constraints are properly loosened for plugins
while maintaining stability guarantees.

https://claude.ai/code/session_01CBpcwXYZjzexKkM9Cf57Kb

* treat all modifiers the same

* docs: add backoffice npm package structure documentation

Add comprehensive section to CLAUDE.md explaining:
- Backoffice npm package architecture and plugin model
- Dependency hoisting strategy and version range logic
- How pre-release versions are handled vs stable versions
- Importmap as single source of truth for runtime
- Plugin development implications and expectations

Clarifies that while npm versions constrain types, the actual runtime comes
from importmap, and plugin developers should declare explicit dependencies
rather than relying on transitive deps.

https://claude.ai/code/session_01CBpcwXYZjzexKkM9Cf57Kb

* docs: add npm package publishing guide to backoffice CLAUDE.md

Add comprehensive section explaining:
- Why backoffice uses peerDependencies (importmap provides runtime)
- Dependency hoisting strategy and version range conversion logic
- How pre-release versions are handled differently from stable versions
- Example published peerDependencies showing final output
- Plugin developer guide with dos and don'ts
- Key files involved in the publishing process

Provides clear guidance for plugin developers on version compatibility
and explains the importmap-as-single-source-of-truth architecture.

https://claude.ai/code/session_01CBpcwXYZjzexKkM9Cf57Kb

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-05 11:25:30 +00:00
Niels LyngsøandGitHub 004569146e Block Catalogue: adapt size to the amount of BlockTypes (#21619)
adaptive Block Catalogue size based on amount of BlockType
2026-02-05 11:48:26 +01:00
Niels Lyngsø dfb46be645 remove not existing script from Claude settings 2026-02-05 11:11:40 +01:00
dfd915c6e3 Block List/Grid: Add "Clear" property action. (#21436)
* Enable Clear action for BlockList and BlockGrid editors.

* Add has-value condition to property action manifests.

* Clear manager state when value is undefined.

* Add clear kind property action.

* Register clear property action in block list/grid.

* Remove has value condition.

* Remove unused import.

* Fix missing export.

* move clear controller into kinds/clear folder

* Update manifests.ts

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-02-05 10:10:04 +00:00
Niels Lyngsø 8cea6cb6b5 Merge branch 'main' into v18/dev 2026-02-05 09:06:55 +01:00
Andy Butland ccc815d711 Merge branch 'release/17.2' 2026-02-05 08:23:39 +01:00
Andy ButlandandLan Nguyen Thuy 13fb4a4e09 OEmbed providers: Tighten up resource URL matching for providers (#21583)
* edit regex for oembed flickr

* Apply stricter matching with domain to all embed providers, and validate with unit tests.

* Resolved warnings and added further unit tests.

* Further tightened the URL matching regex for two providers.

* Add regex caching to OEmbedService and unit tests to verify behaviour.

* Restore flickr short URL domain.

* Use https in requests to oembed providers.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-05 07:14:43 +01:00
cd5ef5ff4d OEmbed providers: Tighten up resource URL matching for providers (#21583)
* edit regex for oembed flickr

* Apply stricter matching with domain to all embed providers, and validate with unit tests.

* Resolved warnings and added further unit tests.

* Further tightened the URL matching regex for two providers.

* Add regex caching to OEmbedService and unit tests to verify behaviour.

* Restore flickr short URL domain.

* Use https in requests to oembed providers.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-05 06:00:49 +00:00
35944c6cca External Login Providers: Fixes deleting a member with more than 1 external login provider causes an error. (#21625)
* Correcting flawed sql statement.

* Integration tests for the fix

* Resolve warnings in MemberServiceTests.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-04 20:57:23 +00:00
3a965677e0 Tests: Fix permission controller tests to use correct entity keys (#21613)
* Tests: Fix permission controller tests to use correct entity keys

The GetDocumentPermissionsCurrentUserController, GetMediaPermissionsCurrentUserController,
and GetPermissionsCurrentUserController tests were incorrectly creating user data and
passing user keys to the GetPermissions method. These controllers expect document/media
keys, not user keys.

Updated the tests to create the appropriate content/media types and entities, then pass
the correct keys to properly test the permission endpoints.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-04 18:23:35 +00:00
Laura NetoandGitHub 7cf4c7857f Elements: Add reference tracking and recycle bin query support (#21481)
* Elements: Add reference tracking and recycle bin query support

- Add Element reference tracking API endpoints (referenced-by, are-referenced, referenced-descendants)
- Add Element recycle bin original-parent and referenced-by endpoints
- Add ElementReferenceResponseModel and ElementContainerReferenceResponseModel
- Add IElementRecycleBinQueryService for querying original parents of trashed elements
- Add Element relation type constants for parent tracking on delete
- Add translation strings for Element recycle bin operations
- Refactor RelateOnTrashNotificationHandler to reduce code duplication using generic helper methods
- Add Element and ElementContainer support to RelateOnTrashNotificationHandler

* Elements: Register Element notification handlers for relation tracking

Add Element and EntityContainer notification handlers for:
- RelateOnTrashNotificationHandler (move to/from recycle bin)
- ContentRelationsUpdate (track element content relations)

* Elements: Remove ReferencedDescendantsElementController

Elements are leaf nodes in the folder structure and cannot have
descendants, making this endpoint unnecessary.

* Elements: Fix ElementPickerPropertyEditor reference extraction

The element picker stores element IDs as Guids, not as UDI strings.
Updated GetReferences to deserialize as Guid array and create UDIs
from the Guid values.

* Elements: Fix TrackedReferencesRepository to include Element published state

Add LEFT JOIN to ElementDto and use COALESCE to get the published state
from either DocumentDto or ElementDto, fixing the issue where Element
references returned published = null.

* Elements: Add ReferencedDescendantsElementFolderController

Add endpoint to get referenced descendants of an element folder.
Unlike elements (which are leaf nodes), folders can have descendants
that may be referenced elsewhere.

* Elements: Add integration tests for Element reference tracking

Add TrackedReferencesServiceElementTests covering:
- GetPagedRelationsForItemAsync for Elements
- GetPagedRelationsForRecycleBinAsync for Elements
- GetPagedKeysWithDependentReferencesAsync for Elements
- GetPagedDescendantsInReferencesAsync for Element containers

* Elements: Add management API controller permission tests for Element reference endpoints

- Add ReferencedByElementControllerTests for element referenced-by endpoint permissions
- Add AreReferencedElementControllerTests for element are-referenced endpoint permissions
- Add ReferencedDescendantsElementFolderControllerTests for folder descendants endpoint permissions
- Fix GetManagementApiUrl to respect [FromQuery(Name="...")] attribute for proper URL generation

* Elements: Split OriginalParentElementRecycleBinController into two controllers

Split the controller to follow the controller-per-operation pattern,
consistent with DeleteElementRecycleBinController and
DeleteElementFolderRecycleBinController.

- OriginalParentElementRecycleBinController: for elements
- OriginalParentElementFolderRecycleBinController: for folders

* Elements: Fix user fallback for audit logging in RelateOnTrashNotificationHandler

Update the handler to properly resolve user key for audit logging, using a switch expression
to handle different entity types. Also sets CreatorId on EntityContainer creation.

* Tests: Fix duplicate query parameter in ItemElementItemControllerTests

Remove the ClientRequest() override that was appending a duplicate id query
parameter to the URL. The base MethodSelector already includes the element key
which gets converted to the query parameter by GetManagementApiUrl, causing
the URL to become ?id=<guid>?id=<guid> and model binding to fail.

* Tests: Fix permission controller tests to use correct entity types

These tests were passing on the base branch only because the URL was being
constructed incorrectly (missing query parameters). After be399134f8 fixed
the GetManagementApiUrl helper to properly include FromQuery parameters,
the tests now correctly build URLs and revealed that they were using user
keys instead of the expected document/media/element node keys.

Updated tests to create the appropriate entity type (document, media, or
element) and pass its key to the permission endpoints.

* Tests: Update RelationTypeRepositoryTest for new element relation types

Update expected counts and fix hardcoded ID lookup after new element
reference tracking relation types were added to the system:
- umbElement (RelatedElement)
- relateParentElementContainerOnElementDelete
- relateParentElementContainerOnContainerDelete

Changes:
- Store created test relation type in field to use actual ID instead of
  hardcoded ID 9 which shifted when built-in types were added
- Update GetAll expected count from 9 to 12 (9 built-in + 3 test data)
- Update Count query expected from 6 to 8 (aliases starting with "relate")

* Refactor: Rename methods in RelateOnTrashNotificationHandler for clarity

Rename methods and parameters to better describe their purpose:
- DeleteRelationsOnRestore → DeleteOriginalParentRelationsOnRestore
- CreateRelationsOnTrashAsync → CreateOriginalParentRelationOnTrashAsync
- relationTypeAlias → originalParentRelationTypeAlias
- relationTypeName → originalParentRelationTypeName

These names clarify that the methods handle "original parent" relations
used for restoring items from the recycle bin, not all relations.

* Tests: Fix ReferencedDescendantsElementFolderControllerTests expectations

- Use unique folder names to prevent conflicts between test runs
- Add assertion to verify folder creation succeeds
- Correct expected status codes for Editor and Writer to OK (not NotFound)

The NotFound responses were caused by folder creation failures due to
duplicate names, not actual permission restrictions.

* Tests: Add success assertions to Element controller test setup methods

Add Assert.IsTrue checks after service calls in test setup to ensure
test prerequisites are correctly established before running actual tests.
This prevents silent failures in setup from causing misleading test results.

Assertions added for:
- ElementContainerService.CreateAsync (9 tests)
- ElementEditingService.CreateAsync (19 tests)
- ElementEditingService.MoveToRecycleBinAsync (6 tests)
- ElementContainerService.MoveToRecycleBinAsync (3 tests)

* Elements: Fix MapReference to return un-enriched response when entity not found

Return the mapped response model instead of null when the matching entity
cannot be found for enrichment. This preserves basic reference information
even when variant data cannot be loaded, preventing valid references from
being silently dropped.

Also clean up ElementContainerReferenceResponseModel formatting.

* Fix: Guard GetSlimEntities against empty keys to prevent loading all entities

* Fix: Return ParentIsTrashed status when original parent is in recycle bin

* Breaking: Remove duplicate sync notification handler interfaces

Remove INotificationHandler<ContentMovedToRecycleBinNotification> and
INotificationHandler<MediaMovedToRecycleBinNotification> interfaces along
with their obsolete sync Handle methods. Only the async handlers should
be implemented.

* Tests: Simplify TrackedReferencesServiceElementTests

- Simplify assertions in Get_Descendants_In_References test
- Create Element3 after folder creation to avoid unnecessary update

* Revert: Remove changes to be moved to separate PRs

Revert EntityTypeContainerService.CreateAsync CreatorId change and
permission controller test changes - these should be addressed in
separate PRs.

* Revert: Remove GetMediaPermissionsCurrentUserControllerTests changes

This change should be addressed in a separate PR for v17.

* Refactor: Move recycle bin audit logging to services

Move audit logging for recycle bin operations from RelateOnTrashNotificationHandler
to the individual services (ContentService, MediaService, ElementEditingService,
ElementContainerService). This simplifies the notification handler and keeps audit
logging closer to the operations being performed.

- Simplify audit messages to "Moved to recycle bin from parent {parentId}"
- Add AuditMoveToRecycleBin helper methods to Content and Media services
- Add AuditMoveAsync helper methods to Element services
- Remove unused audit dependencies from RelateOnTrashNotificationHandler
- Add obsolete constructor bridge for backwards compatibility

* Refactor: Extract GetParentIdFromPath extension method

Add GetParentIdFromPath string extension to consolidate duplicate logic
for extracting parent ID from entity path strings. This replaces 5
instances of the same path parsing pattern across services and handlers.

- Add GetParentIdFromPath to StringExtensions.Parsing.cs
- Inline audit calls in ContentService, MediaService,
  ElementEditingService, and ElementContainerService
- Update RelateOnTrashNotificationHandler to use the new extension
- Add unit tests for the new extension method

* Refactor: Make CreateOriginalParentRelationOnTrash synchronous

Remove unnecessary async from CreateOriginalParentRelationOnTrash since
the method contains no async operations. Update handlers to return
Task.CompletedTask directly.
2026-02-04 14:54:50 +00:00
5fe5a0febf Elements: Implement validation for Element editing endpoints (#21562)
* Elements: Implement validation for Element editing endpoints

Move ValidateCulturesAndPropertiesAsync and GetCulturesToValidate from
ContentEditingService to ContentEditingServiceBase, enabling reuse in
ElementEditingService.

- Implement ValidateCreateAsync and ValidateUpdateAsync in ElementEditingService
- Update Element API controllers to return validation results properly
- Update all inheriting services (Media, Member, Blueprint) with new params

* Elements: Add validation tests for ElementEditingService

- Add tests for ValidateUpdateAsync and ValidateCreateAsync
- Cover invariant, culture variant, and permission-based validation scenarios

* Fix bad merge

* Removed unused fields

* Removed old editor UI

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-02-04 13:35:54 +00:00
Andy Butland d4ee843a01 Merge branch 'main' into v18/dev 2026-02-04 12:06:42 +01:00
9b99d36cbf Picker: Add pagination to search results (#21593)
* add paging UI to picker search results

* implement paging in collection picker data source example

* Hide pagination when all items loaded

* Use paging object for search requests

* Forward paging params in server search queries

* Set default page size in PickerSearchManager

* Use args.paging for skip/take in search

* Update src/Umbraco.Web.UI.Client/src/packages/core/picker/search/picker-search-result.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Reset pagination page when updating query

* dim the box while searching

* Delay loader appearance with fade-in

* Track executed search query and use in results to prevent UI flickering when entering in the search field

* Skip update when dataType is undefined

* Cancel tree loads on context destroy

* fix pagination labels

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-04 10:53:44 +01:00
af359e9f40 Code Documentation: Add XML documentation to all public members in Umbraco.Core (#21471)
* Umbraco.Core: add XML documentation to all public members

Add comprehensive XML documentation comments to all public classes,
interfaces, methods, properties, constructors, and enums in Umbraco.Core
to resolve SA1600 StyleCop warnings.

- Document ~2,500+ files across all folders (Services, Models,
  Notifications, Configuration, Cache, etc.)
- Use <summary>, <param>, <returns>, <remarks> tags as appropriate
- Apply <inheritdoc/> for interface implementations
- Use <see cref="..."/> for type references
- Preserve all existing comments

This eliminates approximately 15,500 SA1600 warnings from the project.

* Revert any code changes in the PR.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-04 09:35:20 +00:00
2917e5be97 Routing: Fix URL aliases not stored for variant content with shared alias property in DocumentUrlAliasService (#21571)
* Fix issue where URL aliases on variant content with a shared property were not being recorded.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-04 09:54:20 +01:00
Niels Lyngsø c48ef57a84 Merge branch 'main' into v18/dev 2026-02-04 09:20:08 +01:00
Niels LyngsøandGitHub 1ab1311a90 Duplicate to: switch to split icon (#21616)
switch to split icon, from 'enter', to make distinguishable from move
2026-02-04 09:02:29 +01:00
bd3d2e1a3f Tiptap RTE: Add delete action support for RTE blocks (#21615)
Block RTE: Add delete action with undo support

Adds a delete button to RTE block entries that removes blocks from
both the editor HTML and the block manager data. Implements an
HTML-first deletion approach that enables Ctrl+Z undo support by
leveraging the existing _filterUnusedBlocks mechanism.

- Add delete button to block-rte-entry action bar
- Add pendingDeletions state to manager for HTML-first deletion flow
- Modify entries context to use pending deletion mechanism
- Add Tiptap API observer to process pending deletions
- Remove blocks from editor via ProseMirror transactions

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 09:00:21 +01:00
3a1f308e9c Updates Umbraco templates, removes framework choice, makes LTS version a wildcard (#21430)
* Updates UmbracoProject template

Removes the framework choice from the template configuration as it's not used and was out of date.

Updates the LTS version to a wildcard to allow minor version updates and mean this doesn't need to be updated all the time!

Updates the description in the dotnet version generated property

* Removes unnecessary build flag

* Remove Custom Version symbol

It doesn't show up in the template anyway and has been marked as obsolete

* Remove framework from Extension template also as not used

* fix: update dotnet new syntax in pipeline

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: NguyenThuyLan <116753400+NguyenThuyLan@users.noreply.github.com>
2026-02-04 12:56:57 +07:00
Andy Butland 0c3d1d7058 Merge branch 'main' into v18/dev 2026-02-03 17:14:16 +01:00
f9abf0ad18 Management API: Add endpoints, service and repository methods for retrieving the allowed parents for content types (#21586)
* Document Types returns a list of allowed parent keys

* Media types included

* Minor fixes to namespace etc.

* Tests

* Fixing breaking change

* Correcting requested changes

* Corrected requested changes

* Removed unnecessary usings, aligned naming between service, repository and tests.
Add a new status for the default implementation (NotImplemented felt more correct than NotFound).
Updated inheritance in service layer so we maintain the NotFound behaviour for member types.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-03 15:36:08 +01:00
b99547db50 Documents: Remove deprecated entityType from property values (closes #21567) (#21609)
Documents: Remove deprecated entityType from property values

The entityType property on property values was causing "Unsaved Changes"
modal to appear after saving documents with RTE blocks. This occurred
because the server data source added entityType when reading, but
setPropertyValue did not preserve it when updating values.

Since entityType on UmbElementValueModel is deprecated and marked for
removal in v18, the cleanest fix is to stop adding it in the server
data source mapping.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 14:18:10 +01:00
3ab7a03254 Content Editor: Fix display of validation hint badge on tabs (#21595)
* Fix display of validation hint related to a tab.

* Update position of the badge.

* Change position for last tab.

---------

Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-02-03 10:13:50 +00:00
Niels LyngsøandGitHub aa334ad3bc MCP: Basic setup for MCP in sourcecode (#21061)
Basic setup for MCP
2026-02-03 10:59:04 +01:00
Andy Butland eda9857200 Merge branch 'main' into v18/dev 2026-02-03 09:37:26 +01:00
dependabot[bot]andJacob Overgaard 21ece43091 Bump lodash
Bumps the npm_and_yarn group with 1 update in the /tests/Umbraco.Tests.AcceptanceTest directory: [lodash](https://github.com/lodash/lodash).


Updates `lodash` from 4.17.21 to 4.17.23
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-03 09:26:03 +01:00
Andy ButlandandGitHub 9915fd3cc5 Media Types: Add public constant for Folder media type GUID (#21597)
* Add and use a constant for the folder media type GUID identifier.

* Use defined constant and avoid lookup for folder media type when searching for media items.
2026-02-03 09:16:11 +01:00
32e7b13944 Performance: Implement key-based caching for data type and template repositories (#21280)
* Add failing tests illustrating the lack of data type caching by key.

* Implement cache by key in data type repository.

* Apply same for template repository look-ups by key.

* Add tests verifying that content types are already cached by Id and key.

* Use correct default for creator Id in data type builder for tests.

* Use non-obsolete constructor in test.

* Ensured a deleted data type or template is cleared from the by key cache.

* Add IReadRepository implementations

* Utilize by-key repo access in service layers

* Fix test

* Safeguard against potential null reference exception

---------

Co-authored-by: kjac <kja@umbraco.dk>
2026-02-03 08:25:52 +01:00
46b96f3811 Global Elements - take one (#21431)
* CRUD + folders + API

* Fix infinite recursion

* Distributed cache handling for Elements

* Publishing for Elements (incl. refactor)

* Fix bad file name

* Added "foldersOnly" option to the siblings endpoint

* Update src/Umbraco.Core/Models/UmbracoObjectTypes.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* API for publishing elements

* Published element cache (WIP)

* Fix delete at repo level

* Fixing up a little tests

* Element picker property editor

* Added tests to prove published element status

* Move scheduled content keys to base abstraction

* Add request caching for published element creation (similar to published document creation)

* Apply conditional appcache access to elements as well

* Fix test build errors

* Fix merge from main

* Fix merge

* Add cache invalidation on update (like content and media)

* Move element (incl. tests)

* Element copying

* Add items endpoint incl. variation info at item level

* Make the Element tree items look like Document tree items (with variations)

* Rename all things ElementType to DocumentType

* Move ElementRepository to the right place

* Fix auditing after merge (changes from #19357)

* Fix dates after merge (changes from #19822)

* Fix NPoco querying after merge (changes from #20184)

* Fix various build errors after merge

* Move containers

* Add migration to create element tables

* Re-implement #21105 at base class level

* Fix merge

* Add element tree recycle bin + move element to/from recycle bin

* Controllers for move to recycle bin + recycle bin root

* Support element containers in recycle bin (no controllers)

* Handle error cases for element moves and add more tests

* Do not allow creation of IPublishedElement for trashed elements

* Amend recycle bin controller output and add children controller

* Regenerate OpenApi.json with Element APIs

* Housekeeping: Organize element container service tests

* Fix bad housekeeping

* Add missing siblings controller for recycle bin

* Add "delete from recycle bin" and "empty recycle bin" operations (including API)

* Updated OpenApi.json to reflect new endpoints

* Added `CreateDate` to `ElementTreeItemResponseModel`

Marked `ElementRecycleBinItemResponseModel.DocumentTypeReferenceResponseModel` as nullable.

* Re-generated OpenAPI.json

* Add configuration endpoint for Elements

* Explicitly unpublish published elements when restoring from recycle bin.

* Elements: Remove invalid templateId from ElementVersionDto index definitions (#21384)

* Persistence: Remove invalid templateId from ElementVersionDto index definitions

The ElementVersionDto had index definitions that referenced templateId in
their IncludeColumns, but the ElementVersion table only has id and published
columns. This caused SQL Server clean installs to fail with error 1911:
"Column name 'templateId' does not exist in the target table or view."

This was likely a copy-paste error from DocumentVersionDto which does have
a templateId column.

* Ignore Cannot_Create_Element_Based_On_NonElement_ContentType for the time being

---------

Co-authored-by: kjac <kja@umbraco.dk>

* Fix the ordering of items in the tree

* It's 2026 now...

* Fix missing project structure

* Amend empty recycle bin

* Elements: Fix element recycle bin node insertion on SQL Server (#21390)

Enable IDENTITY_INSERT before inserting the element recycle bin node with an explicit ID, then disable it afterward. This fixes the migration failing on SQL Server with "Cannot insert explicit value for identity column" error.

* Fix count trashed children

* Moved newly added entity service tests to an isolated, per-test DB class so they do not interfere with the existing per-fixture DB tests

* Elements: Element start node permissions (#21375)

* Add Element start node support for Users and UserGroups

- Add StartElementId to UserGroup and element start nodes to User
- Add UserStartNodeFolderTreeControllerBase for tree filtering with folder support
- Update ElementTreeControllerBase to use start node filtering
- Add ElementTreeItemResponseModel.NoAccess property for "no access" items
- Add UserExtensions methods for element start node calculation
- Update User/UserGroup API models and factories
- Add database migration for startElementId column
- Add SectionAccessForElementTree authorization policy

Note: Granular element permissions deferred for future implementation

* Add element root access for default user groups on fresh install

Set StartElementId = -1 for Administrators, Writers, Editors, and
Translators user groups in DatabaseDataCreator, giving them element
root access on fresh installations (matching their content/media access).

* Add multi-type support to UserStartNodeEntitiesService

Added overloads to RootUserAccessEntities, ChildUserAccessEntities, and
SiblingUserAccessEntities that accept multiple UmbracoObjectTypes. This
enables querying for Elements and ElementContainers in a single call
rather than requiring separate queries for each type.

Also added GetAll and GetPagedChildren overloads to IEntityService and
IEntityRepository to support querying multiple object types efficiently
with a single database query.

* Add integration tests for Element start nodes with mixed hierarchy

Added UserStartNodeEntitiesServiceElementTests with a mixed hierarchy
structure containing both containers and elements at each level:
- Level 1: Containers (C1-C5) and Elements (E1-E3)
- Level 2: Child containers (C1-C1 through C1-C10) and Elements (C1-E1, C1-E2)
- Level 3: Leaf elements (C1-C1-E1 through C1-C1-E5)

This tests scenarios where containers and elements are siblings, ensuring
the access filtering works correctly for mixed-type queries.

Also refactored Content and Media tests to use a shared base class
(UserStartNodeEntitiesServiceTestsBase) to reduce code duplication.

* Add Library section for Elements

- Rename Constants.Applications.Elements to Library
- Add SectionAccessLibrary authorization policy
- Add library mapping to SectionMapper
- Grant Library section access to Administrators, Writers, and Editors on fresh install
- Update TreeAccessElements to use Library section

* Add Element tree controller authorization tests

Add integration tests for RootElementTreeController and
ChildrenElementTreeController to verify section-based
authorization works correctly for the Element tree endpoints.

* Fix ReadOnlyUserGroup not passing startElementId to constructor

The obsolete 13-parameter constructor was passing `null` instead of
the actual `startElementId` value to the next constructor, causing
user groups to appear to have no element start node access.

Also update UserFactory.ToReadOnlyGroup to pass the Description
parameter to the ReadOnlyUserGroup constructor.

* Add Element controller authorization tests

Add authorization tests for Element CRUD, Folder, RecycleBin, and Item
controllers to verify user group access permissions.

Tests cover Admin, Editor, Writer, SensitiveData, Translator, and
Unauthorized user groups for each controller endpoint.

* Re-generated OpenApi.json

* Fix Element start node handling to use ElementContainer object type

- Update UserStartNodeFolderTreeControllerBase to query both folder and
  item object types when filtering by user start nodes
- Fix UserGroupPresentationFactory to use ElementContainer instead of
  Element when resolving element start node IDs/keys

* Revert ByKeyElementController to use synchronous Task.FromResult

The method doesn't have any async operations, so async/await adds
unnecessary overhead.

* Fix UserPresentationFactory to use ElementContainer for element start nodes

Element start nodes reference ElementContainer (folders), not Element items.

* Add recycle bin start node access test for Element controllers

- Add WithStartElementId to UserGroupBuilder
- Add ElementRecycleBinControllerTestBase with shared test verifying
  users with non-root element start nodes cannot access recycle bin
- Update all Element recycle bin tests to use the new base class

* Fix UserGroupPresentationFactory and Element test section alias

- Use ElementContainer instead of Element for start node lookups in
  IReadOnlyUserGroup overload
- Use Constants.Applications.Library for Element test section alias

* Add obsolete User constructor overload for backward compatibility

- Add obsolete constructor without startElementIds parameter that delegates
  to the new constructor with an empty array
- Improve XML documentation for all User constructors

* Elements: Move NoAccess property to FolderTreeItemResponseModel base class

This allows both elements and folders to indicate access status in the tree.

* Elements: Add API versioning attributes to SiblingsElementTreeController

* Elements: Add integration tests for element tree start node permissions

Add tests to verify that users with element start node restrictions can only see
and access elements within their permitted hierarchy.

* Group test files

* Remove type check from GetAllPaths overload

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>

* Elements: Add rollback (#21393)

* Services, repos and tests

* Endpoints for Elements versioning

* Add extra test to prove handling of pinned versions

* Renaming from PR review

* Update tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ElementVersionCleanupServiceTest.cs

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

* More code clean-up after review

* Use correct deleting/deleted versions notifications

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

* Elements: Regenerate OpenApi.json

* Elements: Add default and granular permissions for Element controllers (#21385)

* Add Element start node support for Users and UserGroups

- Add StartElementId to UserGroup and element start nodes to User
- Add UserStartNodeFolderTreeControllerBase for tree filtering with folder support
- Update ElementTreeControllerBase to use start node filtering
- Add ElementTreeItemResponseModel.NoAccess property for "no access" items
- Add UserExtensions methods for element start node calculation
- Update User/UserGroup API models and factories
- Add database migration for startElementId column
- Add SectionAccessForElementTree authorization policy

Note: Granular element permissions deferred for future implementation

* Add element root access for default user groups on fresh install

Set StartElementId = -1 for Administrators, Writers, Editors, and
Translators user groups in DatabaseDataCreator, giving them element
root access on fresh installations (matching their content/media access).

* Add multi-type support to UserStartNodeEntitiesService

Added overloads to RootUserAccessEntities, ChildUserAccessEntities, and
SiblingUserAccessEntities that accept multiple UmbracoObjectTypes. This
enables querying for Elements and ElementContainers in a single call
rather than requiring separate queries for each type.

Also added GetAll and GetPagedChildren overloads to IEntityService and
IEntityRepository to support querying multiple object types efficiently
with a single database query.

* Add integration tests for Element start nodes with mixed hierarchy

Added UserStartNodeEntitiesServiceElementTests with a mixed hierarchy
structure containing both containers and elements at each level:
- Level 1: Containers (C1-C5) and Elements (E1-E3)
- Level 2: Child containers (C1-C1 through C1-C10) and Elements (C1-E1, C1-E2)
- Level 3: Leaf elements (C1-C1-E1 through C1-C1-E5)

This tests scenarios where containers and elements are siblings, ensuring
the access filtering works correctly for mixed-type queries.

Also refactored Content and Media tests to use a shared base class
(UserStartNodeEntitiesServiceTestsBase) to reduce code duplication.

* Add Library section for Elements

- Rename Constants.Applications.Elements to Library
- Add SectionAccessLibrary authorization policy
- Add library mapping to SectionMapper
- Grant Library section access to Administrators, Writers, and Editors on fresh install
- Update TreeAccessElements to use Library section

* Add Element tree controller authorization tests

Add integration tests for RootElementTreeController and
ChildrenElementTreeController to verify section-based
authorization works correctly for the Element tree endpoints.

* Fix ReadOnlyUserGroup not passing startElementId to constructor

The obsolete 13-parameter constructor was passing `null` instead of
the actual `startElementId` value to the next constructor, causing
user groups to appear to have no element start node access.

Also update UserFactory.ToReadOnlyGroup to pass the Description
parameter to the ReadOnlyUserGroup constructor.

* Add Element controller authorization tests

Add authorization tests for Element CRUD, Folder, RecycleBin, and Item
controllers to verify user group access permissions.

Tests cover Admin, Editor, Writer, SensitiveData, Translator, and
Unauthorized user groups for each controller endpoint.

* Re-generated OpenApi.json

* Fix Element start node handling to use ElementContainer object type

- Update UserStartNodeFolderTreeControllerBase to query both folder and
  item object types when filtering by user start nodes
- Fix UserGroupPresentationFactory to use ElementContainer instead of
  Element when resolving element start node IDs/keys

* Revert ByKeyElementController to use synchronous Task.FromResult

The method doesn't have any async operations, so async/await adds
unnecessary overhead.

* Fix UserPresentationFactory to use ElementContainer for element start nodes

Element start nodes reference ElementContainer (folders), not Element items.

* Add recycle bin start node access test for Element controllers

- Add WithStartElementId to UserGroupBuilder
- Add ElementRecycleBinControllerTestBase with shared test verifying
  users with non-root element start nodes cannot access recycle bin
- Update all Element recycle bin tests to use the new base class

* Fix UserGroupPresentationFactory and Element test section alias

- Use ElementContainer instead of Element for start node lookups in
  IReadOnlyUserGroup overload
- Use Constants.Applications.Library for Element test section alias

* Add obsolete User constructor overload for backward compatibility

- Add obsolete constructor without startElementIds parameter that delegates
  to the new constructor with an empty array
- Improve XML documentation for all User constructors

* Elements: Add granular permissions for Element controllers

Add Element-specific permission actions:
- ActionElementBrowse, ActionElementNew, ActionElementUpdate, ActionElementDelete
- ActionElementPublish, ActionElementUnpublish, ActionElementMove, ActionElementCopy

Add permission infrastructure:
- ElementPermissionResource for authorization checks
- ElementPermissionHandler and ElementPermissionRequirement
- ElementPermissionService and IElementPermissionService
- ElementPermissionAuthorizer and IElementPermissionAuthorizer
- ElementGranularPermission model
- ElementPermissionMapper for user group permissions

Update Element controllers with authorization:
- Add HandleRequest pattern via CreateElementControllerBase and UpdateElementControllerBase
- Pass cultures for Publish/Unpublish authorization
- Apply authorization checks to Element CRUD and publishing operations

* Elements: Add default element permissions to user groups

Add element action permissions for Admin, Editor, Writer, and Translator
user groups in DatabaseDataCreator, mirroring the document permission pattern.

* Elements: Add current user element permissions endpoint and fix folder authorization

- Add GetElementPermissionsCurrentUserController endpoint to get current user's element permissions
- Fix ElementPermissionService to authorize both Element and ElementContainer (folders)
- Add GetElementPermissionsAsync to IUserService/UserService
- Add ElementNodeNotFound to UserOperationStatus
- Add IEntityService.GetAll overloads for multiple object types

* Elements: Move NoAccess property to FolderTreeItemResponseModel base class

This allows both elements and folders to indicate access status in the tree.

* Elements: Add default implementation to IUserService.GetElementPermissionsAsync

Adds a default throwing implementation to avoid breaking existing IUserService implementations when this method is added.

* Elements: Add API versioning attributes to SiblingsElementTreeController

* Elements: Add integration tests for element tree start node permissions

Add tests to verify that users with element start node restrictions can only see
and access elements within their permitted hierarchy.

* Add granular permissions to element rollback

* Update src/Umbraco.Core/Actions/ActionElementCopy.cs

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>

* Elements: Use lowercase action aliases for consistency

Update all Element action aliases to lowercase to comply with the
IAction.Alias requirement for case-sensitive filesystems. Also rename
ActionElementNew alias from "elementNew" to "elementcreate" to match
the document action's "create" alias pattern.

* Elements: Refactor UserService permission methods to reduce duplication

Consolidate GetMediaPermissionsAsync, GetDocumentPermissionsAsync, and
GetElementPermissionsAsync into a single shared implementation via
a new private GetContentPermissionsAsync helper method.

---------

Co-authored-by: kjac <kja@umbraco.dk>

* Add element folder "item" endpoint

* Include "isTrashed" in folder response models

* Update TODOs

* Rollback a few unnecessarily breaking signature changes

* Use schema constants from #21327

* Elements: Add admin group element permissions during upgrade (#21452)

Grant the admin user group access to the element root node and all
element permissions when upgrading from a previous version. This
ensures parity with fresh installations where the admin group receives
these permissions by default.

* Elements: Fix Writer expected status codes in Element controller permission tests

Update WriterUserGroupAssertionModel to expect Forbidden for operations
that Writers don't have permission for, matching Document controller
behavior and the actual permissions assigned to the Writer group.

Changed from OK/Created to Forbidden:
- CopyElementControllerTests
- DeleteElementControllerTests
- MoveElementControllerTests
- MoveToRecycleBinElementControllerTests
- PublishElementControllerTests
- UnpublishElementControllerTests
- Folder/DeleteElementFolderControllerTests
- Folder/MoveElementFolderControllerTests
- Folder/MoveToRecycleBinElementFolderControllerTests
- RecycleBin/DeleteElementRecycleBinControllerTests
- RecycleBin/DeleteElementFolderRecycleBinControllerTests
- RecycleBin/EmptyElementRecycleBinControllerTests

* Elements: Fix duplicate column name in DocumentVersionDto index definition

The ForColumns parameter incorrectly specified PublishedColumnName twice
instead of IdColumnName and PublishedColumnName, causing SQL Server to
reject index creation with "duplicate column names" error on new installs.

* Add missing element mapper and allow deleting element types with active elements (#21483)

* Add missing element mapper and allow deleting element types with active elements

* Update src/Umbraco.Core/Services/ContentTypeService.cs

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

* Update src/Umbraco.Core/Services/ContentTypeService.cs

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

* Update src/Umbraco.Core/Cache/Refreshers/Implement/ElementCacheRefresher.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Review comment: ReadOnlyUserGroup constructor

* Update comments in ElementEditingService

* Add Library section access to content, media, and member tree policies

* Elements: Add Elements access to data type, document type, and relation authorization policies (#21501)

Add Elements access to data type, document type, and relation authorization policies

* Amend merge from v18/dev

* Global Elements: Backoffice UI implementation (#21410)

* chore: generate new openapi types

* Added package/module for "Library"

* Added default dashboard for Library section

* [WIP] Adds "Elements" package module

Basics of the tree/menu.

* Adds entity-actions for Create and Reload

* Adds entity-action for Move To

* Adds collection workspace view

for root and folders

* Adds entity-action for Duplicate To

* "Reload Children" should only be for root & folders

* Reworked Library sidebar app

Replaced with Elements sidebar app
Removed the Library menu

* chore: generate new openapi types

* Added Item repository

* Added Reference repository

* Added Element Recycle Bin

Tree, menu, entity-actions, workspace (collection view)

* Adds "umb-element-tree-item" to identify the `isTrashed` state

* Re-added Library sidebar app

Removed Library dashboard (we'll figure it out later)

* Recycle Bin type tweaks

* [WIP] Element "Create" modal

* Reverted Element "Create" modal, to use create-options + picker

* chore: generate new openapi types

* Added Element Detail Repository

* [WIP] Element Workspace + Context

* Elements: Add workspace views for edit and info

Add edit and info workspace views to the Element workspace:
- Edit view using shared 'contentEditor' kind pattern
- Info view displaying state tag, dates, element type, and ID
- Menu structure context for tree navigation
- Split-view component for variant editing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Elements: Add save action and trash state handling

- Add Save workspace action using UmbSubmitWorkspaceAction
- Add isTrashed property to UmbElementDetailModel
- Implement trash state change handling with read-only guard
- Add recycle bin event listeners for trash/restore actions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Adds Workspace actions for Save, Publish, Scheduled Publish

* Adds Element Configuration repository

* Adds mock handle + data for Elements

* Adds Publish and Unpublish entity actions for Elements

Implements context menu actions for publishing and unpublishing elements
directly from the tree. Uses existing modals and publishing repository.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* package-lock.json update

* Adds bulk entity actions for Publish, Unpublish, Move and Trash

* Localization keys + code tweaks

* Adds reusable `emptyRecycleBin` `collectionAction` kind

* Adds `emptyRecycleBin` for Element Recycle Bin collection

* Element Recycle Bin refactoring

Working towards folder support

* Relations: exported entity-action types

* Restructured "Element Folder" code

* Restructured "Trash" entity-bulk-action code

* Adds `trashFolder` `entityAction` kind

* Adds "Trash" entity-action for Element Folders

* Tidy-up / restructuring

* [WIP] Element Picker property-editor UI

making use of an Elements property-data-source,
with Entity Picker.

* Renamed `UmbElementPropertyDatasetContext` to `UmbElementWorkspacePropertyDatasetContext`

to de-duplicate a class name clash with the underlying base class.

* Added "entity-data-picker" importmap

Exposing the "umb-input-entity-data" component

* Reworking the "Element Picker" property-editor UI

to reuse the Entity Picker internal input component

* Implemented "Element Item Data Resolver" helper

* chore: generate new openapi types

* Fixed up the mocks and types

with new Element start nodes and `noAccess` fields.

* Added UI for "Elements Start Nodes"

* Added "entity-data-picker" export to the Vite config

* Fixed Element Folder picker for "start nodes"

* Adds UI for Element's User Permissions

* Adds Element User Permission condition

Implemented the user permissions for entity actions, etc.

* Adds UI for Element's Granular Permissions

* Adds element-folder item repository

* Element Recycle Bin: implemented `isTrashed`

* Fixed mock folder data manager

* Adds move entity-action for element-folder

Implements the Move action for element folders using the
ElementService.putElementFolderByIdMove API endpoint.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix typos and element tag name mismatches in elements package

- Fix typo 'now' -> 'no' in user-permissions/types.ts
- Fix HTMLElementTagNameMap tag name to match @customElement decorator
- Fix typo 'TDOD' -> 'TODO' in element-detail.server.data-source.ts
- Fix missing 'u' prefix in element-picker tag name declaration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Ignore local Claude settings in UI Client

* Updated workspace assign access,

to disable root access when start nodes are selected.

* Elements: Display trashed state in Element workspace info panel (#21542)

The state tag in the Element workspace info view was missing a case
for the TRASHED state, causing trashed Elements to incorrectly display
"Not created" instead of "Trashed".

* Elements: Fix folder link in recycle bin list view (#21543)

The trashed element name column always used the element workspace path
pattern, causing folders clicked in the recycle bin list view to show
"Not found". Now checks isFolder and uses the correct workspace path
pattern for folders vs elements.

* Elements: Add missing delete permission conditions to recycle bin actions (#21547)

The Empty Recycle Bin collection action and the folder delete entity
action were missing user permission conditions, making them visible
to users without delete permission.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
Co-authored-by: Lee Kelleher <leekelleher@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 07:46:31 +01:00
50d089c2f9 Repositories: Quote table, column and alias names (closes #21451) (#21577)
* quote table, column and alias names with SqlSyntaxProvider methods in raw sql

* refactoring private methods into new file as internal methods,
refactor new extensions into another file

* refactor GetAlias method

* Double check the change

* improve code health

* change new static classes into public static partial class NPocoSqlExtensions

* resolve some Copilot review suggestions

* revert Copilot suggestion because it decreases code health

* revert test

* revert refactoring for CodeScene

* delete obsolete Test

* remove new methods and updates, which are not relevat for this PR

* prepare for additional states in the future

* don't mix string building methods

* fix SQL injection danger

* fix test for reverted methods

* another SqlSyntax issue

* Add additional unit and integration tests verifying the refactorings made in the PR.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-02-03 07:36:57 +01:00
Nhu DinhandGitHub df37ae9839 E2E: QA Bumped version of test helper to fix the failing tests (#21596) 2026-02-02 21:07:20 +07:00
769cd808f1 TipTap: Avoid empty target attribute on links (#21572)
* Remove the default empty target tag for links, so the target attribute is only output when it has a value.

* Tiptap Link extensions: defaults `target` value to `null`

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-02-02 12:42:02 +00:00
Jacob OvergaardandGitHub 6aeffe7a6e build(deps): bumps @umbraco-ui/uui to 1.17.0-rc.5 (#21569) 2026-02-02 12:40:30 +00:00
Andy ButlandandGitHub 574c9bed6c Content Types: Fix deletion of properties without containers (closes #21566) (#21585)
Fix issue with deleting properties that are not in containers.
2026-01-30 14:41:09 +01:00
Niels LyngsøandGitHub 8f0555182c Content Type Designer: transfer root properties when creating first tab. (#21582)
* transfer root properties when creating a new tab

* fix controller lifecycle
2026-01-30 13:28:57 +01:00
Niels Lyngsø 731b10b07a formatting 2026-01-30 11:13:10 +01:00
Niels Lyngsø f1d32e41e0 lint 2026-01-30 11:12:35 +01:00
dc218ac1bf Repositories: Use FirstOrDefault over ExecuteScalar for GUID and nullable types (closes #21448) (#21552)
* Squash merged  "v173/20453-21446-21448-FirstOrDefault-vs-ExecuteScalar" into "v173/21448-FirstOrDefault-vs-ExecuteScalar"

* resolce Copilot code review comments

* revert to ExecuteScalar<string>

* revert to Database.ExecuteScalar<string>

* revert .FirstOrDefault<long>(query) and its async variant to .ExecuteScalar<long>(query). It is fine for PostgreSql too.

* Remove the test added for verifying NPoco behaviour (it's not needed in the code base moving forward)

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-29 15:38:48 +00:00
Jacob Overgaard 79cce7b574 bumps lockfile 2026-01-29 12:39:59 +01:00
Jacob Overgaard feb2827d16 Merge branch 'release/17.2' 2026-01-29 12:39:27 +01:00
Jacob Overgaard ae10b6685a generates api types 2026-01-29 12:12:31 +01:00
Andy Butland 6122cfc201 Bump version to 17.3.0-rc. 2026-01-28 14:22:09 +01:00
Niels LyngsøandGitHub c1b0672ce0 Content Value Transformation: Clean out values when property-type variation transforms (#21557)
* cleanup values of property when property type variation changes

* implement handling segments in transformation
2026-01-28 14:16:13 +01:00
Laura Neto 7d73588c99 Merge branch 'main' into v18/dev 2026-01-28 13:27:22 +01:00
8efdfcd341 Backoffice: Exclude invariant options for culture-variant properties in preset builder (#21555)
* Exclude invariant options for culture-variant properties in preset builder

* Add unit test verifying the fix.

* added a few more unit tests

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-01-28 11:30:54 +00:00
3c7a1ad2de Entity Signs: Refactor Entity Sign Bundle to use Popover API. (#21490)
* Refactor entity sign tooltip to use popover API.

* Refactor popover positioning and styling logic.

* Add preview icons to entity sign bundle.

* Improve entity sign preview rendering and popover state.

* Refactor entity sign popover and sign container styles.

* Remove unused index parameter.

* Update menu item background color styles.

* Revert commented lines.

* Refactor entity sign popover rendering logic.

* Refactor popover sign creation into separate method.

* keep previews on hover

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-01-28 10:37:20 +00:00
5485a31f75 Tiptap RTE: Resolves inline blocks being set as dirty (closes #17749) (#21546)
* Resolves RTE inline blocks being flagged as dirty

Fixes #17749

* Deprecated `displayInline` field

* Update src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/block/block.tiptap-api.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 09:52:45 +00:00
Jacob OvergaardandGitHub 345a075706 Dependencies: Bumps @umbraco-ui/uui to 1.17.0-rc.4 (#21538)
* build(deps): bumps @umbraco-ui/uui to 1.17.0-rc.2

* build(deps-dev): bumps @umbraco-ui/uui to rc.3 to fix deps mess

* build(deps): bumps @umbraco-ui/uui to 1.17.0-rc.4
2026-01-28 09:52:08 +00:00
Niels LyngsøandGitHub 046c7d207d Content Type Designer: Property Layout updates (#21544)
* remove alias id

* adjust spacing and sizing for improved space in the layout
2026-01-28 09:26:37 +00:00
a5a67a4381 Translations: Missing translations in user permission (#21541)
* Fix issue localization of user permission

* add localize to create button

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-01-28 10:13:39 +01:00
Andy ButlandandGitHub e259cd0fd3 External Logins: Handle duplicate key race condition intermittently triggered in ExternalLoginRepository (#21551)
Handle duplicate key race condition in ExternalLoginRepository.
2026-01-28 06:27:27 +01:00
bohdansolovieandGitHub b5559eb9e8 View Engines: Make ProfilingViewEngine._inner private and modernize string formatting (#21550)
improvement(web): make ProfilingViewEngine._inner private and modernize string formatting

- Changed internal readonly Inner field to private readonly _inner field
- Replaced string.Format calls with string interpolation
- Removed TODO comment
2026-01-27 17:51:24 +01:00
f2c351df64 Skip leading whitespace in ufm parser (#21509)
* Skip leading whitespace in ufm parser

* UFM: Update start function to also skip leading whitespace

The tokenizer was updated to allow whitespace after opening braces,
but the start function still used a string pattern without whitespace
tolerance. This updates start to use a pre-compiled regex that matches
the tokenizer behavior, and adds an additional test case for the
documentation example format.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-01-27 16:02:27 +00:00
Andy Butland 4e6481abd9 Bumped test dependencies to latest minor or patch. 2026-01-27 15:30:43 +01:00
Andy Butland b40c17582a Bump dependency on SixLabors.ImageSharp for ImageSharp2. 2026-01-27 15:30:13 +01:00
Lee KelleherandGitHub af7a21723d Tiptap RTE: Upgraded to latest v3.x (#21493)
* Upgraded Tiptap to v3.13.0

* Remove eslint disable comments

* Update notes in externals

* `TextDirection` is now part of Tiptap core

* Upgraded Tiptap to v3.16.0

* The `addOptions()` typing error still persists in v3.16.0

* Resolved the export issue

* Removed unrequired `@ts-expect-error`

This came from an upstream merge.
2026-01-27 12:04:48 +00:00
Jacob OvergaardandGitHub fc5a8a0536 build(deps-dev): bumps login dependencies to latest (#21539) 2026-01-27 11:39:33 +01:00
7d813667c3 Content/Media: Fix deadlock when performing certain operations in parallel (closes #21125) (#21526)
* Move MediaTree write lock before MediaSavingNotification to prevent deadlock

Fixes a deadlock that could occur when saving multiple media items in parallel
when a MediaSavingNotification handler acquires a MediaTree read lock. The
previous ordering allowed two threads to each acquire read locks in their
notification handlers, then both attempt to upgrade to write locks, causing
a classic lock upgrade deadlock in SQL Server.

By acquiring the write lock before publishing the notification, the deadlock
scenario is avoided. Since the write lock is lazy, it only materializes at the
database level when actual queries are made, so notification handlers doing
in-memory work won't hold the lock.

* Apply same fix to MediaService.Delete method

* Apply same fix to DeleteVersions, DeleteVersion, and Sort methods

* Apply same fix to ContentService methods

Move WriteLock before notifications in:
- Save (single and batch)
- Delete
- DeleteVersions
- DeleteVersion
- Copy

* Apply the same pattern to MemberService.

* Add integration tests to verify the fix.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-27 11:08:35 +01:00
Andy ButlandandGitHub 138818acde Members: Fix misleading error message on change password with incorrect current password (#21504)
* Provide correct validation error message on member change password with incorrect current password.

* Rework to use MembersErrorDescriber.
2026-01-27 10:37:28 +01:00
kjac 40c91262e6 Merge branch 'main' into v18/dev 2026-01-27 10:32:50 +01:00
Nhu DinhandGitHub 79753eaf82 E2E: QA Updated acceptance tests for collection view search and document type group (#21522) 2026-01-27 16:00:12 +07:00
Andy ButlandandGitHub 647aa08586 Dependencies: Bump to latest minor/patch versions (#21540)
Bump dependencies to the latest minor or patch.
2026-01-27 08:34:18 +00:00
Nhu DinhandGitHub 9deffead21 E2E: QA Added acceptance tests for multi url picker validation message (#21226)
* Added tests for multi url picker validation message

* Added more tests - not done

* Updated more tests for multi url picker validation message

* Removed unused file

* Bumped version

* Make tests run in the pipeline

* Reverted npm command
2026-01-27 08:31:41 +00:00
Niels Lyngsø 31f23204f3 Merge branch 'main' into v18/dev 2026-01-27 09:19:30 +01:00
Andy ButlandandGitHub d5d93ff1e0 Templates: Allow underscore as first character in template alias (closes #21534) (#21536)
Use a custom regex for validating template aliases that allows underscores.
2026-01-27 08:32:37 +01:00
7ad3d2f68f Content picker: Fix bug where dynamic root children are not correctly available for selection (closes #21477 and #21537) (#21535)
Fix bug content picker dynamic root children not selected properly

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2026-01-27 08:27:52 +01:00
Andreas ZerbstandGitHub 2fb1221d68 Dotnet Template: Fix trailing comma in appsettings.json (#21529)
Fix trailing comma in global settings
2026-01-27 03:34:18 +00:00
efb8aaf87b Dark mode: Added color variable to code block in the system information dialog to make it readable (#21532)
* added color variable to code-block to make it readable in dark mode

* Update src/Umbraco.Web.UI.Client/src/packages/core/components/code-block/code-block.element.ts

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-26 18:07:17 +00:00
2e80b996cf Media: Prevent creation of media with GUID v7 keys when using incompatible path scheme (closes #21440) (#21457)
* Prevent creation of media items with GUID version 7 keys when a media scheme is registered that doesn't support this GUID version.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix log message formatting.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-01-26 16:29:37 +01:00
Andy ButlandandGitHub 883b6a4d5d Models Builder: Fix nested generic type handling in WriteClrType (#21429)
* Add support to models builder for nested generic types.

* Fixed existing warnings, added further tests, renamed tests for clarity.

* Add defensive validation for generic brackets passed to SplitGenericArguments.

* Fix failing unit tests.
2026-01-26 15:32:48 +01:00
6946783b74 Content types: Allow adding composition with clashing property alias when property is being removed (closes #21298) (#21527)
* Content types: Allow adding composition with clashing property alias when property is being removed

* Further assert on property coming from the composition.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-26 14:32:34 +00:00
ad759e9311 Block editors: Fix false pending changes indicator for invariant block editor with culture-variant blocks (closes #21223) (#21292)
* Block editors: Fix false pending changes indicator for invariant BlockList with culture-variant blocks (closes #21223)

When a document with a culture-variant content type has an invariant BlockList property containing culture-variant blocks, and you publish all languages for the first time, the content would incorrectly show as having unpublished changes.

The root cause was inconsistent JSON serialization order between EditedValue and PublishedValue. Two fixes were applied:

1. Sort block item values by culture before serialization in both `FromEditor` and `MergePartialPropertyValueForCulture` to ensure consistent ordering.

2. Add `[JsonIgnore]` to `BlockItemData.Udi` property since this computed property differs between save and publish paths.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/PropertyEditors/BlockListElementLevelVariationTests.Publishing.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixed failing integration tests.

* Fix backwards compatibility for legacy UDI format in JSON deserializatio

* Tidy up, remove unused parameters.

* Fixed failing E2E test with copy blocks.

* Separate handling of udi and values in deserialization from current and legacy format, to correctly fix previously failing integeration and E2E tests.

* Fixed failing unit test.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-26 14:51:16 +01:00
00794f48c5 Tiptap RTE: Adds link (umbLink) support to styleMenu API (#21494)
* Adds link (`umbLink`) support to the Style Menu api

* Tiptap RTE: Fix toggleClassName to handle multi-class strings

The toggleClassName command now properly tokenizes the className parameter
to handle space-separated classes (e.g., "btn btn-primary"). Previously,
the entire string was treated as a single token, causing duplicates and
preventing class removal.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Tiptap RTE: Add ensureUmbLink command for idempotent link creation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 14:24:29 +01:00
Niels LyngsøandGitHub 2c5466755a Block List Editor: Describe that Single Block Mode is deprecated (#21512)
mark Single Block Mode as deprecated
2026-01-26 13:07:54 +00:00
DreamandGitHub 7438dd7c84 Backoffice: Redirect to list view after entity deletion (#21456)
Backoffice: Redirect to list view after entity deletion

When an entity is deleted from its detail workspace, the UI now redirects
to the parent list view and shows a success notification instead of staying
on the deleted entity's page showing a 404 error.

Changes:
- Dispatch UmbEntityDeletedEvent after successful deletion
- Show success notification toast on deletion
- Listen for delete event in workspace editor and navigate to backPath
2026-01-26 12:54:25 +00:00
Andy ButlandandGitHub 868ac50b79 Media: Only add deleted suffix to URLs for trashed media when recycle bin protection is enabled (#21412)
Fix protection for media URLs such that they only apply for trashed media.
2026-01-26 13:41:01 +01:00
Sven GeusensandGitHub 897b6ccac6 Load Balancing: Tracking difference CM and CD redirect and post-logout URIs in load-balanced environments (#21432)
* Integration tests for #21138

* Make OpenId redirect and postlogout uris support load balanced environments

* Applied review suggestions

* Fix unit test mocks
2026-01-26 12:08:42 +01:00
997df3d92b Performance: Optimize property retrieval and authorization checks in collection views (#21470)
* Introduce new method overloads and repository implentation, such that a collection view response only loads properties it needs.

* Use non-obsolete method overloads throughout.

* Add unit tests to verify property value retrieval.

* Don't load templates for collection view content retrieval.

* Optimize access checks by verifying the full collection rather than one at a time, and avoid the need to retrieve full content items.

* Added obsoletion messages and aligned behaviour of content and media permission service checks.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Return key in TreeEntityPath collection response, avoiding a later look-up of the key by Id.

* Resolve breaking changes to interfaces.

* Fix further breaking change.

* Additional assert for test verifying property loading for a non-existing property.

* Refactored repositories to avoid having method parameters related to templates on non-document and base content repositories.

* Remove check that verifies all provided keys are found when doing permission checks (although arguably correct, it's a behavioural change, and can also be argued it's corect as is).

* Introduce variable for permission set permissions.

* Provide functional default implementation on FilterAuthorizedAsync.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-26 11:53:53 +01:00
e4df87123c Testing: Ensure ordering for paged descendants tests (closes #21446) (#21447)
* Squash merge Squash merged v173/20453-fix-more-sql-syntax-issues int v173/20453-fix-more-sql-syntax-issues-squash (copy of main)

* fix 2 unit test

* Replace nameof(DTO.COLUMN_NAME) by constant, because it leads to casing issues for case sensitive databses

* fix Copilot review comments

* resolve review comments

* replace more hard coded strings

* fix test

* fix review comments

* fix database schema

* fix database schema

* fix database schema and ResultColumn reference names

* Update src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* add comment  from review

* fix two reference column names

* fix breaking change

* fix typo

* Remove unnecessary attributes

* mark 2 unsused DTO classes as obsolete

* reverted change of class UnionHelperDto adding [Column("...")] attributes again, because some integration tests for PostgreSQL provider fail without them. Again a case sensitivty issue.

* replace nameof reference names,
make all column name const consistent

* use NPoco dto instead of raw sql,
extend ISqlSyntaxProvider to handle some sql issues

* reduce complexity

* remove currently unsused extensions to ISqlSyntax

* add missing methods to ISqlSyntaxProvider and SqlSyntaxProviderBase

* add another missing methods to ISqlSyntaxProvider and SqlSyntaxProviderBase

* fix Copilot review comments and build errors

* update ISqlSyntaxProvider and SqlSyntaxProviderBase

* ensure GetPagedDescendants returns ordered by path entities as default

* resolve review comments

* fix review comments

* Update src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix Copilot comment

* fix wrong Copilot suggestion

* quote more column names

* resolve review

* Apply suggestions from code review

* synced interface and base class

* Revert "synced interface and base class". For an interface's default implementation, NotImplementedException makes more sense.

This reverts commit cf01cd01fc.

* Fixed remaining code warnings in DatabaseSchemaCreator.

* follow Cotpilot's review suggestion

* revert implementation and fix test

* use default

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-26 09:36:13 +00:00
c6370e39a7 Recycle Bin: Adds emptyRecycleBin collection action kind for Documents and Media (#21482)
* Adds reusable `emptyRecycleBin` `collectionAction` kind

* Adds `emptyRecycleBin` collection-action to documents

* Adds `emptyRecycleBin` collection-action to media

* Removes `api` export

since the condition is eagerly loaded.

* Fixes type annotations and JSDoc comments

- Uses correct generic type `UmbCollectionHasItemsConditionConfig` in `UmbCollectionHasItemsCondition`
- Corrects JSDoc `@augments` tag in `UmbEmptyRecycleBinCollectionAction`

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fixed linting errors

* Refactors execute() to reduce cyclomatic complexity

Extracts tree refresh logic into private #reloadChildrenOfEntity() method.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update src/Umbraco.Web.UI.Client/src/packages/media/media/recycle-bin/manifests.ts

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Removed code comment

as caused ambiguity.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-26 09:25:37 +00:00
08863332d2 Disabled the generation and upload off the docfx csharp api docs. (#21521)
* Disabled the generation and upload off the docfx csharp api docs.

* Add comment explaining why job is disabled

* Added comment on second job

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-26 09:07:00 +00:00
f483946c4d Code Quality: Added missing documentation to the Umbraco.Cms.Api.Common project (#21465)
* Added missing code documentation to the Umbraco.Cms.Api.Common project

* Remove duplicate XML summary for All constant

Removed duplicate XML summary documentation for the All constant.

* Removed inline comments no longer required now the information has been moved to XML header remarks

* Fix indentation on refactored path segment extraction in SubTypesSelector

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-26 07:28:56 +00:00
e7624364ed Database Providers: Add support for providers offering sequence and null casting support (closes #21418) (#21419)
* Squash merge Squash merged v173/20453-fix-more-sql-syntax-issues int v173/20453-fix-more-sql-syntax-issues-squash (copy of main)

* fix 2 unit test

* Replace nameof(DTO.COLUMN_NAME) by constant, because it leads to casing issues for case sensitive databses

* fix Copilot review comments

* resolve review comments

* replace more hard coded strings

* fix test

* fix review comments

* fix database schema

* fix database schema

* fix database schema and ResultColumn reference names

* Update src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* add comment  from review

* fix two reference column names

* fix breaking change

* fix typo

* Remove unnecessary attributes

* mark 2 unsused DTO classes as obsolete

* reverted change of class UnionHelperDto adding [Column("...")] attributes again, because some integration tests for PostgreSQL provider fail without them. Again a case sensitivty issue.

* replace nameof reference names,
make all column name const consistent

* use NPoco dto instead of raw sql,
extend ISqlSyntaxProvider to handle some sql issues

* reduce complexity

* remove currently unsused extensions to ISqlSyntax

* add missing methods to ISqlSyntaxProvider and SqlSyntaxProviderBase

* add another missing methods to ISqlSyntaxProvider and SqlSyntaxProviderBase

* fix Copilot review comments and build errors

* update ISqlSyntaxProvider and SqlSyntaxProviderBase

* resolve review comments

* fix review comments

* Update src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix Copilot comment

* fix wrong Copilot suggestion

* quote more column names

* resolve review

* Apply suggestions from code review

* synced interface and base class

* Revert "synced interface and base class". For an interface's default implementation, NotImplementedException makes more sense.

This reverts commit cf01cd01fc.

* Fixed remaining code warnings in DatabaseSchemaCreator.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-24 09:16:15 +00:00
83300221fe Log Viewer: Fix polling interval reset when changing intervals (closes #21507) (#21508)
* fix(log-viewer): prevent polling toggle reset when changing interval

Fixes issue where changing polling interval would reset the button to 'Polling' state instead of applying the new interval immediately.

- Remove togglePolling() call from closePoolingPopover() method
- Update setPollingInterval() to restart polling with new interval if already enabled

Fixes #21507

* refactor(log-viewer): extract polling start logic and fix regression

- Extract polling start logic into #startPolling() helper method
- Fix regression: enable and start polling when interval is selected while polling is off
- Update togglePolling() to use the helper method for consistency

Addresses feedback on PR #21508

---------

Co-authored-by: Gittensor Miner <miner@gittensor.io>
2026-01-23 17:17:02 +01:00
af81e258b4 Fix for the client side circular dependency. (#21464)
* Fix for the client side circular dependency.

This should fix the circular dependency without causing any breaking changes to the public APIs.

This issue is detailed here:
https://github.com/umbraco/Umbraco-CMS/issues/21463

* refactor UMB_MODAL_MANAGER_CONTEXT to avoid circular dependency

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-01-23 15:53:42 +00:00
aa4a33251a Content Types: Root properties (#21500)
implement root properties

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-01-23 12:47:17 +00:00
Mads RasmussenandGitHub e7c63b19b9 Modal: Add 'in modal' condition to modal package (#21503)
* Add 'is modal' condition to modal package

Introduces a new 'is modal' condition for extension manifests, allowing actions to be conditionally permitted based on modal context. Updates user collection action manifests to use this condition, preventing certain actions when inside a modal. Includes implementation, configuration, manifest registration, and tests for the new condition.

* rename from is modal to in modal
2026-01-23 12:27:36 +00:00
Niels LyngsøandGitHub 16f9bc7cd7 Block List & Block Single: Use property value in validation check (Fixes #21313) (#21491)
use this.value as source for the validation
2026-01-23 12:12:20 +00:00
Niels LyngsøandGitHub 3b5e938492 Property Value Preset Builder: accept variant options (#21382)
property value preset builder to use variant options
2026-01-23 10:04:37 +00:00
ea76efafc1 Dictionary: Add configurable value search functionality (#21200)
* added dicationary value search active only with config param set

* Removed code smell, by reducing nesting

* Renamed configuration value to EnableValueSearch.
Added integration tests to verify search results.

* update query to return correct values for each language in the overview

* Use OptionsMonitor and add additional assert to verify fix to indication of which languages have translations.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-23 09:47:39 +01:00
1a68d39272 Variants Sorting: Sort by language name (fix #21408) (#21435)
* Sort at last by language name

* ensure document language picker is sorted as variant selector

* Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor to avoid inline methods

* transform into a function

* revert config file commit

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-23 09:47:14 +01:00
e53b8bcc52 Variants Sorting: Sort by language name (fix #21408) (#21435)
* Sort at last by language name

* ensure document language picker is sorted as variant selector

* Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor to avoid inline methods

* transform into a function

* revert config file commit

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-23 09:18:52 +01:00
Andy ButlandandGitHub fee3cc7352 Redirect Tracking: Handle empty string in redirect tracker when restoring from recycle bin (#21488)
Handle empty string in redirect tracker when restoring from recycle bin.
2026-01-23 14:25:51 +09:00
Nhu DinhandGitHub 3f3362e0f3 E2E: QA Updated tests for granular permission in content to match the changes (#21478) 2026-01-23 04:07:50 +00:00
Nicklas KramerandGitHub 8f55885829 Data Types: Allows transparency for the approved colors in the color picker. (#21495)
Fixing regex and adding test
2026-01-23 10:34:20 +09:00
8f6ebcdcf6 Picker: Support embedded Collections in the Collection Item Picker Modal (#21392)
* Add alias property to collection config interface

Introduced an 'alias' property to the UmbCollectionItemPickerModalCollectionConfig interface

* render collection element when modal is configured with an alias

* expose a picker modal route

* use collection in use picker

* adjust spacing

* add config option for selectOnly

* dynamic modal alias

* support selectable entity item ref

* wip entity data picker collection + ref and card views

* Add entity collection item card extension type + default elements

* implement user collection item card

* fix selection events

* map to prop

* add prop/attr for href

* add support for which detail properties to show

* update type import

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/item/entity-collection-item-card/entity-collection-item-card.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* import card in correct file

* Fix event listener binding for selection events

* implement disabled property for collection item cards

* init commit of collection item ref extension

* fix imports

* add element interface

* Implement UmbEntityCollectionItemElement interface in item cards

Added the UmbEntityCollectionItemElement interface to document and user collection item card elements for improved type safety and consistency. Updated type exports to include the new interface.

* Update collection item ref to use uui-ref-node

Replaces the placeholder div with a uui-ref-node component, passing relevant item properties and event handlers. Adds dynamic icon rendering using umb-icon.

* Refactor entity collection item elements to use shared base

Introduces a new abstract base class for entity collection item elements, consolidating shared logic for card and ref variants. Updates card and ref element implementations to extend the new base, and refactors extension manifest interfaces for consistency. This improves maintainability and reduces code duplication.

* use class instead of magic string

* Use entity collection item card in picker view

Replaces the placeholder card markup with the <umb-entity-collection-item-card> component, enabling selection and deselection functionality for items in the entity data picker card collection view.

* Update entity item ref to collection item ref

Replaces <umb-entity-item-ref> with <umb-entity-collection-item-ref> in the picker collection view. Adjusts event handlers and select-only logic to improve selection behavior and component consistency.

* utilise ref and card kind for picker views

* introduce ref and card collection view kinds

* Utilise card kind for user collection view

* Add item-specific href support to collection views

Introduces a requestItemHref method to collection contexts for retrieving item-specific hrefs. Updates card, ref, and user table collection views to use these hrefs, enabling dynamic linking for collection items. Refactors user table name column layout to accept href via value prop instead of constructing it internally.

* Update ManifestCollectionView import path

Changed the import of ManifestCollectionView from '../extensions/types.js' to '../view/types.js' to reflect its new location.

* remove unused

* use size medium for entity collection item picker

* use box

* render entity actions

* use edit path builder for user links

* rename method

* Revert "rename method"

This reverts commit 4df577688e.

* Update collection-default.context.ts

* make type lint ignore unused args with an underscore

* temp remove unused

* only make collection vie selectable if there are any registered bulk actions

* don't render name link if there is no href

* fix imports

* Render selection actions only if bulk actions exist

* use selectable state

* Update language-table-collection-view.element.ts

* Update language-table-collection-view.element.ts

* Update card-collection-view.element.ts

* clean up

* Refactor collection views to use shared base class

* refactor(collection): parallelize href fetching and make method private

* docs(examples): update collection example to use card and ref kinds

* docs(examples): add icon property to collection example data model

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/view/types.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update collection-bulk-action.manager.test.ts

* Removed duplicate and redundant '@typescript-eslint/no-unused-vars' rule definitions, consolidating the configuration to use only 'argsIgnorePattern'.

* Handle missing user href in name column layout

Replaces the user name link with a span when the href property is not provided, preventing broken links in the user table name column layout.

* Update user-table-name-column-layout.element.ts

* pass modal data and value to routable modal

* Update picker-input.context.ts

* support selectableFilter

* scaffolding of a collection text filter extension

* Refactor collection text filter to use API interface

* Fix incorrect tag

* Update types.ts

* Update collection-text-filter.extension.ts

* Add cancelation to debounced search on destroy

* clean up

* add js docs

* two way binding of filter value

* clean up

* Add collection text filter manifest example

Introduced a new filter manifest for the example collection and updated the main manifests file to include it. This enables a text filter extension for the example collection.

* Delete unused element and context

* Update src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/user-group-collection.context-token.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update user-group-table-collection-view.element.ts

* support search for tree item and collection item pickers

* add spacing between collection ref items

* add margin between picker search result items

* remove spacing after last item

* remove padding in search results

* Update collection-item-picker-modal.element.ts

* move select only logic to collection selection manager

* add tests for collection selection manager

* change to filter label instead of search

* delete unused user grid collection view

* Select-only mode is now only disabled when all items are deselected, rather than on every deselection.

* prepare umb table for pickers

* utilize UmbCollectionViewElementBase in user table collection view

* remove console log

* handle select all and select item from same event

* bulk actions workaround

* add bulk action in collections feature toggle

* remove unused method

* make fields optional to avoid a breaking change

* remove unused import

* fix typescript errors

* adjust search styling

* hide with css

* fix ts errors

* Add modal data support to picker input context

Introduces methods to set and get modal data in UmbPickerInputContext, allowing base configuration for picker modals. Updates modal data handling to merge stored modal data with provided data for both direct picker opening and modal route setup.

* Fix bulk action manager test initialization

Added calls to setConfig in tests to properly initialize the observer before subscribing to hasBulkActions. Simplified the test logic for checking emissions when actions are present.

* Update tree-picker-modal.element.ts

* Update picker-search-result.element.ts

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/view/umb-collection-view-element-base.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Use ifDefined for modal route in user input button

* Use ifDefined for href binding in entity data picker

* Fix collection alias binding in item picker modal

* wire up user table collection view with selectableFilter

* clean up controller aliases

* Update collection-item-picker-modal.element.ts

* Update collection-item-picker-modal.element.ts

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-22 15:24:09 +00:00
Andy ButlandandGitHub eca3e91af0 Management API: Fix document URLs returning all languages for invariant content (closes #21459) (#21473)
Fix display of all languages for URLs for invariant documents.
2026-01-22 11:41:01 +01:00
Niels LyngsøandGitHub 718e35f483 Media: Picker Modal types export (Fixes #21265) (#21329)
fix media modal exports
2026-01-22 10:03:18 +00:00
Niels LyngsøandGitHub ca8f6f59bd Entity Signs: Embed Api & Element for performance (#21480)
embed api & element
2026-01-22 09:18:31 +00:00
338f650274 Content-Type Designer: Transfer tab when moving property to inhertied tab (Fixes #20789) (#21234)
* enable async method

* ensure container is local to the owner content type

* no need to await anyhow

* handle moved groups

* Update src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-properties.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-22 07:09:45 +01:00
Lee KelleherandGitHub 995e3bde6f Task: De-duplicate TypeScript class names (#21474)
De-duplicate TypeScript class names
2026-01-21 20:57:16 +01:00
7f162201e6 Fixes #20665 - Password change error msg (#21257)
* Fixes #20665 - Password change error msg

In order to show the right validation message:
 - the repository code always notifies the validation failure message
    (or a default failure message if none is received)
 - in the data-source code, tryExecute is called with the option
    to disable the default notification

* Return the original error instead of faking success

---------

Co-authored-by: Emma L Garland <1649855+emmagarland@users.noreply.github.com>
2026-01-21 13:48:25 +00:00
d7dbe39dd3 Routing: Add DocumentUrlAliasService for optimized URL alias lookups (closes #21383) (#21396)
* Implement document alias cache and service to optimize content finder by alias.

* Renamed to DocumentUrlAlias. Fixed issues on start-up.

* Remove tracking of root ancestor.

* Optimize cache key, tidy up tests, move domain matching to content finder.

* Handle language and document deletes.

* Align further with document URL service.

* Code tidy.

* Fixed comment.

* Refactor scope handling to avoid nested scopes

Extract CreateOrUpdateAliasesInternalAsync to process documents without
creating their own scope. Both CreateOrUpdateAliasesAsync and
CreateOrUpdateAliasesWithDescendantsAsync now create a single scope
and call the internal method, avoiding unnecessary nested scope creation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Extract CreateOrUpdateAliasesInternalAsync to process documents without
creating their own scope.

* Only return a document for a match under a domain if the document is found under the domain of the current request.

* Fix failing integration tests.

* Apply suggestions from code review.

* Ensured language to culture code map is updated when a language isn't found in the cached map.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 13:52:45 +01:00
b2801e6555 Backoffice: Fix event listener memory leaks in auth, dropzone, actions, and router (#21458)
fix(backoffice): resolve event listener memory leaks in auth, dropzone, actions, and router

Fixes memory leaks in 4 components where event listeners registered with .bind(this) could not be properly removed because each .bind() call creates a new function reference.

Changes:
- auth.context.ts: Convert #onStorageEvent to arrow function property
- dropzone-media.element.ts: Convert 4 drag handlers to arrow function properties
- entity-actions-dropdown.element.ts: Convert handler and add disconnectedCallback
- router-slot.element.ts: Convert handler and add proper cleanup in disconnectedCallback

Solution: Arrow function properties maintain consistent references while preserving 'this' context, enabling proper listener removal.

Testing:
- Added unit tests for auth.context.ts
- All builds pass
- Linter passes
- No breaking changes

Documentation:
- Added "Event Listener Cleanup Pattern" section to clean-code.md
- Added "Event Handler Guidelines" section to style-guide.md

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-21 11:12:09 +00:00
594b64e2a9 Tiptap RTE: Optimize umb-input-tiptap initialization and rendering (#21070)
* refactor(rte): Replace misleading Promise.all with sequential awaits

The inner awaits in Promise.all([await ..., await ...]) made the operations
sequential anyway. Since #loadEditor() depends on _extensions being populated,
sequential execution is correct - this change makes the intent clearer.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(rte): Cache toolbar and statusbar emptiness checks

Instead of calling .flat() on every render to check if toolbar/statusbar
have items, compute the boolean once when values are set in #loadEditor().
This avoids unnecessary array operations during render cycles.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* perf(rte): Pre-compute extension styles during initialization

Instead of calling unsafeCSS() on each style during every render cycle,
collect and process styles once in #loadEditor() and store the result
in _extensionStyles. This avoids repeated CSS processing during renders.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/tiptap/components/input-tiptap/input-tiptap.element.ts

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-21 10:19:21 +01:00
acd0aae48e DevOps: Adds check:duplicate-class-names devops script (#21460)
* Adds `check:duplicate-class-names` devops script

* DevOps: Improve `check:duplicate-class-names` script

- Fix example path in JSDoc comment
- Add support for `export default class` declarations
- Add `--ignore-stories` flag to exclude story files from detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Added try/catch on reading file contents

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-21 10:18:52 +01:00
Jacob OvergaardandGitHub d4c3813410 Dotnet Template: Removes unused setting SanitizeTinyMce (#21467)
chore: removes unused setting `SanitizeTinyMce`
2026-01-21 08:53:59 +00:00
Nikolaj GeisleandGitHub 5d664538f0 Examine: Check for registered populators before emptying indexes (#21455)
* Check for registered populators before emptying indexes

* Update can rebuild to also use HasRegisteredPopulator
2026-01-21 08:33:03 +01:00
Andy ButlandandGitHub c8f897879c Performance: Fix thread safety and optimize cache updates in PublishStatusService after content changes (#21415)
* Resolved potential thread safety issues with PublishStatusService.

* Only update published status in content cache refresher if within a publish or unpublish operation.
2026-01-21 06:41:55 +00:00
cee47613a6 Move media-type guid strings into constants partial (#21461)
* move media-type guid strings into constants partial

* missed one.

* Update src/Umbraco.Core/Constants-MediaTypes.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add member type GUID constants too.

* Removed member type incorrectly recorded as a built-in data type.

* Reuse constant in obsolete GUID constant.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-21 06:25:45 +00:00
ac1a0a46df Document URL Cache: Ensure URLs are rebuilt after upgrade and prevent duplicate initialization (closes #21337) (#21379)
* Remove rebuild of document URLs during migration, instead ensuring they will run after migration is complete and Umbraco is running.

* Avoid unnecessary second rebuild of document URL cache after startup with migration that has already triggered a rebuild.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-21 06:54:56 +01:00
8f571fe51b Rollback: Add toggle for diff display (closes #18518) (#21426)
* Add a toggle, defaulted to off, for display of diffs on the rollback view.

* Used only label for checkbox.

* Align formatting across translations for diffHelp key.

* Changed the checkbox to a toggle

UI semantics, checkboxes imply selection, whereas toggles imply activation.

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-01-20 15:44:04 +00:00
Niels LyngsøandGitHub a3b4e922d9 Performance: Use import maps to save requests (#21363)
Use import maps to save requests
2026-01-20 14:27:11 +00:00
fd7a2c6a5a Content picker: Prevent selection of document/member type containers when configuring allowed types (closes #21356) (#21357)
* Prevent selection of document and member type folders when selecting allowed types for the content picker.

* Added fix for Media Types

* Set `documentTypesOnly` on `umb-input-document-type`

so to disallow selecting element-types.

* Linting

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2026-01-20 12:50:37 +00:00
fd09a24559 Media: Unable to see the "Access denied" view when deep-linking to restricted media nodes (#21442)
* fix: aligns media workspace with document workspace to handle "variants" when calculating routes, which fixes an issue where the "Access denied" view would not be shown

* fix: clear root access flag when selecting specific start nodes

When selecting specific document or media start nodes for a user, the UI now automatically sets hasDocumentRootAccess/hasMediaRootAccess to false.

Previously, if a user group had "Has access to all items" enabled, selecting specific start nodes on the individual user wouldn't clear the root access flag. This caused the backend to add -1 (root access) to the start node list, overriding the specific node selections.

This ensures user-specific start node permissions properly override group-level root access settings.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add length check to prevent rendering router with empty routes array

The render method now checks both that _routes exists AND has length > 0 before rendering the router-slot. An empty array is truthy, so without the length check, the router-slot could be rendered with an empty routes array, causing runtime errors.

This aligns with the original render logic and prevents the TypeError when media tests run.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Fix E2E test URL construction for media workspace deep-linking

The test was constructing an invalid URL by appending the workspace path
directly to the current URL, which included '/collection'. This resulted in:
/umbraco/section/media/collection/workspace/media/edit/ (invalid)

Instead of the correct:
/umbraco/section/media/workspace/media/edit/

The fix removes '/collection' before appending the workspace path, ensuring
the test actually navigates to the workspace editor where the 'Access denied'
view is properly displayed.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Make all tests for media start node run in the pipeline - remember to revert before merging

* Revert npm command before merging

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Nhu Dinh <hnd@umbraco.dk>
2026-01-20 10:42:12 +00:00
2eb2e33f2f Document Tree: Filter tree items based on user browse permissions (closes #21141) (#21173)
* Document Tree: Filter tree items based on user browse permissions

- Add FilterTreeEntities virtual methods to EntityTreeControllerBase for filtering tree entities with total count adjustments
- Override FilterTreeEntities in DocumentTreeControllerBase to filter by ActionBrowse permission
- Extract filtering logic into IDocumentPermissionFilterService for testability
- Add unit tests for DocumentPermissionFilterService

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-20 10:57:13 +01:00
ddffd6ec1e HybridCache: Optimize content type change cache rebuild to resolve SQL timeouts (#21207)
* Complete the scope when no runnable job found. Without this I'm seeing timeouts and lock contention if a long-running document type save operation is running when the first distributed job is requested.

* Run serialization steps of rebuild of content cache in parallel for a small but not insignficant speed optimization.

* Add integration tests for database cache rebuild.

* Optimize rebuild of databaes and memory cache after content type update.

* Add debug log for running distributed job.

* Apply memory cache clear optimization to media.

* Optimize MediaCacheService.RebuildMemoryCacheByContentTypeAsync with lightweight query

Use GetMediaKeysByContentTypeKeys to fetch only media keys instead of loading full ContentCacheNode objects. This matches the same optimization applied to DocumentCacheService.

Also refactors Rebuild() to reuse RebuildMemoryCacheByContentTypeAsync for the memory cache clearing step.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Further updates from code review.

* Further tests for variant documents, composed documents and message pack serialization.

* Fixed failing integration tests.

* Clear the cacje level published content cache on content type change.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-20 09:15:40 +01:00
e206f26e5e Content Picker: Provide "content root" origin for dynamic root (closes #21134) (#21161)
* Provide "content root" origin for dynamic root.

* Update src/Umbraco.Core/DynamicRoot/Origin/ContentRootDynamicRootOriginFinder.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Code tidy.

* Add integration test

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sven Geusens <geusens@gmail.com>
Co-authored-by: Sven Geusens <sge@umbraco.dk>
2026-01-20 06:56:23 +01:00
Chris HoustonandGitHub cbaab6a6f3 Code Quality: Adding XML documentation to Umbraco.Cms.Persistence.EFCore.SQLServer & Umbraco.Cms.Persistence.EFCore.SQLite (#21439)
Adding XML documentation to these two projects.

- Umbraco.Cms.Persistence.EFCore.SQLServer
- Umbraco.Cms.Persistence.EFCore.SQLite
2026-01-20 06:50:24 +01:00
Chris HoustonandGitHub 4f62771135 Code Quality: Resolve 128 SA1600 documentation warnings in Umbraco.Cms.Persistence.Sqlite (#21438)
* fix: Resolve 128 SA1600 documentation warnings in Umbraco.Cms.Persistence.Sqlite

- Added XML documentation comments to interceptors, mappers, and services
- Added TODO (V18) comments to SqliteSyntaxProvider.Format methods (CS0114)
- Updated .csproj TODO comment to follow V18 convention
- CS0114 warnings remain suppressed as fix would be binary breaking

* Fixed the issues Copilot complained about with the documentation and..

Fixed two IDE0270 warnings (null check simplification).
2026-01-20 06:48:32 +01:00
Chris HoustonandGitHub a4e72cbdb1 Code Quality: Adding all missing XML documentation for the Umbraco.Cms.Persistence.EFCore project (#21437)
Adding all missing XML documentation for the Persistence.EFCore project
2026-01-20 06:42:00 +01:00
Chris HoustonandGitHub 8d75277297 Code Quality: Fix CS0659 and CS0661 build warnings in Item test class by removing legacy test and setup of little value (#21399)
* Code Quality: Fix CS0659 and CS0661 build warnings in Item test class

The Item class in test project defined Equals override and equality operators without implementing GetHashCode, causing CS0659 and CS0661 compiler warnings.

Added GetHashCode implementation using RuntimeHelpers.GetHashCode(this) for consistent reference-based equality matching the existing operators behavior.

Removed CS0659/CS0661 from WarningsNotAsErrors in test project as they are no longer needed.

* Code Quality: Remove unused test infrastructure classes

Remove Item, OrderItem, and SimpleOrder classes along with the SimpleOrder_Returns_Null_On_FirstOrDefault_When_Empty test.

These ~370 lines of test infrastructure existed only for a single trivial test that verified FirstOrDefault() returns null on an empty collection - behavior already tested on actual Umbraco collections in the same file.
2026-01-20 06:32:51 +01:00
Andy ButlandandGitHub d4fe1b3783 StringExtensions: Refactor into partial classes and optimize methods (#21370)
* Refactor StringExtensions into multiple files using partial classes.

* Tidy/complete XML header comments.

* Fixed warnings in string extension methods.

* Add unit tests for IsLowerCase and IsUpperCase and optimize the methods.

* Add unit tests for ReplaceNonAlphanumericChars and optimize the method.

* Add unit tests for StringWhitespace and optimize the method.

* Add unit tests for StripHtml and DecodeFromHex and optimize the methods.
Fix too aggressive regex for StripHTML to ensure works only on HTML tags.

* Add unit tests for EnsureStartsWith and EnsureENdsWith and optimize the methods.

* Add unit tests for ToSingleLine and StripNewLines and optimize the methods.

* Fix issues raised in code review.
2026-01-19 19:18:39 +01:00
Andreas ZerbstandGitHub e767914bd0 E2E: QA Added separate emails for the login tests (#21443) 2026-01-19 14:33:56 +00:00
7acdc6ec0b Router: Destroy route component when disconnected (Fixes #21272) (#21318)
destroy route component when disconnected

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-01-19 11:11:26 +01:00
Nhu DinhandGitHub 00971bb55e E2E: QA Fixed failing tests for setting up content notifications (#21441) 2026-01-19 08:39:27 +00:00
Chris HoustonandGitHub 9832603525 Code Quality: Resolve SA1649 warnings (#21401)
* Added the SA1649 to the "No Warnings" section.

Stylecop is trying to enforce filenames that are like:

CancellableObjectEventArgs{TEventObject}.cs

However Umbraco uses CancellableObjectEventArgs.cs

Unless a policy decision is make to follow this stylecop rule, I think it is better to add this rule to the " NoWarn " section, so we don't see it appear at all.

* Revert accidental package-lock.json change

* Renaming files to match the StyleCop patterns.

Except two which would end up having the same names as other file, so these have been renamed as LegacyIScope & LegacyIScopeProvider, with local Pragma warnings disabled for this Style Cop rule.

* Removing the SA1649 from Warnings NOT as Errors.

In other words, if you turn on show warnings as errors, these will show as errors, rather than being suppressed.
2026-01-17 14:35:01 +01:00
Jacob OvergaardandGitHub e485056b8d Bulk Publish: Filter variant options to applicable cultures only (closes #19147) (#21163) 2026-01-16 19:25:22 +01:00
Andy ButlandandGitHub 28a3884adb Revert binary breaking changes from PR #21236 (#21434)
* Revert binary breaking changes from #21236 and comment with a TODO for the next major.

* Further TODO.
2026-01-16 17:46:59 +01:00
Niels Lyngsø 25d3013949 Merge branch 'main' into v18/dev 2026-01-16 17:18:05 +01:00
Mads RasmussenandGitHub 0eaca92615 Backoffice Performance: Inline entry point modules to reduce JS chunk count (#21380)
* change to static import

* add support for passing modules to manifest js property

* Replaces dynamic imports of entry-point.js with static imports across all manifests

* Support statically imported modules in loader functions

Extended loadManifestApi and loadManifestElement to handle already resolved module objects (statically imported modules) in addition to dynamic imports. Updated type definitions in utils.ts to include module export types for loader properties.

* Add tests for loadManifest* functions in extension-api

Introduces unit tests for loadManifestApi, loadManifestElement, and loadManifestPlainJs functions. These tests cover various scenarios including direct class constructors, dynamic and static imports, export prioritization, and edge cases for null and undefined inputs.
2026-01-16 15:18:59 +00:00
Engiber LozadaandGitHub 9ed3186cc2 Content Workspace: Add condition to detect when a content workspace has finished loading. (#21290)
* Added folder and files for the new condition.

* Registered the condition.

* Added an example to test the condition.

* Added the condition in one of examples.

* Renamed condition.

* Fixed linting error.
2026-01-16 15:59:01 +01:00
10c5df892f Notification Container: Make toast notifications announced by screen readers in Chrome. (#21028)
* fix(a11y): Toast notifications not announced by screen readers in Chrome

- Move screen reader live region from Shadow DOM to Light DOM (document.body)
  Chrome doesn't reliably detect ARIA live regions inside Shadow DOM
- Use role="alert" with fresh elements for each announcement instead of
  updating text content of an existing live region
- Fix invalid aria-role="true" attribute (was invalid HTML)
- Fix missing backslash in unicode escape '\u00A0'

The previous implementation had the live region nested 3 levels deep in
Shadow DOM, which Safari handled but Chrome ignored. Creating a new
alert element in Light DOM for each announcement is the most reliable
method across browsers.

Closes #14521

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Removed comment.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-16 15:57:46 +01:00
Niels Lyngsø 90be5d9958 lint fixes 2026-01-16 14:51:20 +01:00
Bjarne FyrstenborgandGitHub 4d5f9ec7ce Focal point: Utility functions (#21264)
Focal point utils
2026-01-16 13:20:19 +00:00
Andy ButlandandGitHub 07e25d681b Media Picker: Respect start node when drag+dropping files directly onto picker (closes #21422) (#21423)
Pass parent unique to the media to the media picker dropzone.
2026-01-16 11:51:45 +01:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>iOvergaardEngiber Lozada
ba7f84c96f Thumbnails: Fix image thumbnails cropping to allow the entire image to be shown as a thumbnail (closes #20347) (#21288)
* Initial plan

* Change object-fit from cover to contain for image thumbnails

Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>

* Add visual demonstration of the fix

Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-01-16 11:50:26 +01:00
Dirk SeefeldandGitHub f36947a947 Replace nameof() by constants of DTO (closes #21303) (#21344) 2026-01-16 10:59:03 +01:00
JeavonandGitHub f6230cd122 Update Umbraco and Starter Kit versions in templates (#21395)
* Update Umbraco version in starterkits template

LTS and Latest should both install 17.0.0, at the moment latest uses Umbraco v17.1.0 but a starter kit version 17.0.0-rc1 which is not a good combo

* Update LTS in template to 17.1.0
2026-01-16 10:04:48 +01:00
a2c743ca43 Persistence Model: Replace some hard coded strings in DTOs (#21327)
* Squash merge Squash merged v173/20453-fix-more-sql-syntax-issues int v173/20453-fix-more-sql-syntax-issues-squash (copy of main)

* fix 2 unit test

* fix Copilot review comments

* resolve review comments

* replace more hard coded strings

* fix test

* fix review comments

* fix database schema

* fix database schema and ResultColumn reference names

* Update src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* add comment  from review

* fix two reference column names

* fix breaking change

* fix typo

* Remove unnecessary attributes

* mark 2 unsused DTO classes as obsolete

* reverted change of class UnionHelperDto adding [Column("...")] attributes again, because some integration tests for PostgreSQL provider fail without them. Again a case sensitivty issue.

* replace nameof reference names,
make all column name const consistent

* Update obsoletion messages

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-16 06:18:53 +00:00
Niels Lyngsø d72d66edfd no delay on forbidden-text animation 2026-01-15 16:35:00 +01:00
9c50476b17 Tree Navigation: Add visual indicators for items with restricted access (#21365)
* Tree pickers: Implement noAccess property UI handling for user start nodes

- Add noAccess observable to document and media tree item contexts
- Add visual styling (grayed out, italic) for noAccess items in tree views
- Update document and media picker input contexts to prevent selection of noAccess items
- Items with noAccess are shown for navigation but cannot be selected in pickers

This implements the UI handling for Feature 63060 "Handle Start Nodes"

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix noAccess implementation and add E2E tests

This commit combines all improvements made to the noAccess property feature:

1. Refactored to use Lit lifecycle methods (updated()) instead of property watchers
2. Added click and keyboard event handlers to prevent navigation
3. Removed disabled attribute that was blocking tree expansion
4. Added comprehensive E2E tests for document and media trees

Critical bug fix: Removed disabled attribute that prevented expansion
- The disabled attribute was blocking ALL interactions including expanding
  tree items to show accessible children underneath noAccess ancestors
- Now only sets aria-disabled="true" for screen readers and removes href
- Click and keyboard event handlers still prevent navigation as intended
- Users can now properly navigate through noAccess ancestors to reach
  their accessible child nodes

E2E test coverage:
- Display noAccess styling (opacity, italic)
- Prevent navigation when clicking noAccess nodes
- Allow expansion of noAccess nodes to show children
- Picker tests skipped pending infrastructure improvements

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Remove aria-disabled manipulation that interferes with tree expansion

The previous implementation set aria-disabled="true" and removed href
from the menu-item in #updateMenuItemAccessibility(). This approach
caused issues with tree expansion functionality.

Removed:
- #updateMenuItemAccessibility() method
- updated() lifecycle hook that called it
- UUIMenuItemElement import (no longer needed)

The click and keyboard event handlers already prevent navigation to
noAccess nodes, so additional DOM manipulation is not necessary.

Test results:
 4 passing: Display styling and prevent navigation work correctly
 2 failing: These appear to be backend issues:
   1. Document expansion: Caret button disabled (backend marking noAccess
      items as not selectable, which disables entire menu-item)
   2. Media expansion: Child media folder incorrectly has noAccess attribute
      (backend data issue - child should be accessible as it's the start node)

The UI implementation is sound. The remaining test failures indicate
backend API issues that need investigation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Fix path comparison bug in UserStartNodeEntitiesService (similar to #21162)

This fixes the same path comparison bug we fixed in PR #21162 but in C# string
comparisons instead of SQL queries.

## Root Cause
Path comparisons without trailing commas caused false matches:
- Path "-1,1001" incorrectly matched prefix "-1,100"
- This marked nodes as ancestors/descendants when they weren't related

## Examples of False Matches
- child.Path = "-1,1001", startNodePath = "-1,100"
  - OLD: "-1,1001".StartsWith("-1,100") = TRUE (bug!)
  - NEW: "-1,1001,".StartsWith("-1,100,") = FALSE (correct!)

- child.Path = "-1,100", startNodePath = "-1,1001"
  - OLD: "-1,1001".StartsWith("-1,100") = TRUE (bug!)
  - NEW: "-1,1001,".StartsWith("-1,100,") = FALSE (correct!)

## Fix Applied (Two Locations)
1. Line 146 (ancestor check): Added comma suffix to child.Path
2. Line 226 (IsDescendantOrSelf): Added comma suffix to both paths

This matches the pattern already used correctly in lines 92 and 191 of the
same file, and mirrors the SQL fix from PR #21162.

## Test Impact
This should fix the failing E2E test where child media folders were incorrectly
marked as noAccess when they were actually the user's start node.

Related: #21162

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Fix remaining merge conflict markers in media-tree-item.element.ts

* Remove E2E agent markdown file (moved to personal space)

* test: adds mock data for noAccess

* feat: moves noAccess subscriber to base class

* test: adds mock data for media

* feat: moves no-access styling to the base class

* fix: media tree items should inherit styling from the base class

* feat: observes noAccess from children and reports back to the base class

* test: spec file should use undefined instead of null

* docs: add comprehensive comments explaining noAccess opt-in pattern

- Document why noAccess is not in base interface (breaking change)
- Explain opt-in pattern with code examples
- Add JSDoc comments to property, event handlers, and CSS
- Reference accessibility considerations (keyboard users)
- Link child class implementations to base class documentation

* test: adds timeout for URL to settle

* fix: allow clicks on accessible children of noAccess tree items

When a tree item has noAccess, child tree items are rendered in its slot.
Previously, the parent's click handler blocked ALL clicks due to event bubbling,
preventing users from navigating to accessible descendants.

Now checks if click originated from a child tree item element using closest().
If it's a child, allow the click. Only block clicks on the noAccess item itself.

Applied to both mouse clicks and keyboard navigation (Enter/Space).

This enables users to navigate through noAccess ancestors to reach their
accessible start nodes (e.g., Root[noAccess] → Child[noAccess] → Grandchild[accessible]).

Fixes tests:
- should allow expansion of noAccess ancestor node to show children (documents)
- should allow expansion of noAccess ancestor media node to show children (media)

* compare with the closest element to see if we are clicking on the element that is blocked or a sub-element that is not

* fix: adds forbidden route in case of no variants

* test: corrects label locator

* test: adds test to check if you can click or deeplink to restricted media

* test: removes .only

* test: removes duplicated tests

* test: adds test for document no-access

* test: add unit tests for user start node path comparison logic

Adds comprehensive unit tests documenting the path comparison fix that prevents
false matches when node IDs are numeric prefixes of other IDs (e.g., 100 vs 1001).

The fix uses trailing commas on both paths to ensure accurate comparison:
- Without fix: "-1,100".StartsWith("-1,10") = true  (incorrect)
- With fix: "-1,100,".StartsWith("-1,10,") = false  (correct)

Tests cover:
- Numeric prefix edge cases (1 vs 10, 10 vs 100, 100 vs 1001)
- Self comparison (start node itself)
- Descendant relationships
- Deep path hierarchies
- Demonstrates the bug without the fix for documentation

19 test cases total, all passing.

* test: removes .only

* fix: do not overwrite forbidden route

* docs: fixes line number in comment

* test: fixes comment

* feat: uses isSelectableContext to disable and scrub 'href' from base element

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-15 16:29:21 +01:00
7dca122a80 NPM: Move Umbraco Package Schema and custom-elements to root level for IDE discoverability (closes #16667) (#17866)
* Adjust build scripts for custom elements and JSON schema generation to be placed at root level, add generation to build for npm and update .gitignore

* fix: updates umbraco package schema location

* git ignores

* fix: outputs the vscode custom elements file at root

* fix: adds generated files to output

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2026-01-15 15:11:26 +00:00
e7de6a8afb Backoffice: Fix login logo popover to display Umbraco branding (closes #21078) (#21413)
* fix(backoffice): use hardcoded Umbraco logo in header popover

Fixes issue where the backoffice header logo popover incorrectly
displayed the LoginLogoImageAlternative setting instead of showing
the Umbraco branding.

Changes:
- Added hardcoded umbraco-logo.svg asset to client project
- Updated backoffice-header-logo component to reference static logo
- Wrapped logo in link to umbraco.com
- Removed dependency on BackOfficeLogo endpoint for popover

The small header logo button still uses <umb-app-logo> and remains
customizable via the BackOfficeLogo setting.

Closes #62866

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* chore: removes link to umbraco.com

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-15 15:27:12 +01:00
d6de4a611a Media Picker: Uploaded files should automatically be selected (closes #21115) (#21409)
* fix(media-picker): auto-select uploaded media items

When uploading media in the media picker modal, uploaded items are now
automatically selected. This works for both single and multiple selection
modes, and correctly handles paginated folders where uploaded items may
not be visible on the current page.

Closes #21115

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(media-picker): navigate to last page after upload

Uploaded media items get the highest SortOrder, placing them on the last
page. This change navigates to the last page after upload so users can
see their newly uploaded items, which are also auto-selected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-15 13:06:00 +01:00
Nhu DinhandGitHub 65d7989c23 E2E: QA Add acceptance tests for user group description (#21404)
* Added tests to create a user group with description

* Clean up

* Moved tests for user group description to other class

* Bumped version

* Make tests run in the pipeline

* Reverted npm command
2026-01-15 10:54:37 +00:00
226162d8f2 Performance: Optimize refresh of hybrid cache for a document by retrieving draft and published in single query (#21407)
* Optimize retrieval of ContentCacheNode for draft and publish in when refreshing the hybrid cache.

* Fixed issue with XML header documentation tags.

* Use is null for consistency

---------

Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
2026-01-15 10:52:21 +00:00
dependabot[bot]andJacob Overgaard b484403b1c Bump the npm_and_yarn group across 2 directories with 1 update
Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client directory: [diff](https://github.com/kpdecker/jsdiff).
Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client/src/packages/core directory: [diff](https://github.com/kpdecker/jsdiff).


Updates `diff` from 7.0.0 to 8.0.3
- [Changelog](https://github.com/kpdecker/jsdiff/blob/master/release-notes.md)
- [Commits](https://github.com/kpdecker/jsdiff/compare/7.0.0...v8.0.3)

Updates `diff` from 7.0.0 to 8.0.3
- [Changelog](https://github.com/kpdecker/jsdiff/blob/master/release-notes.md)
- [Commits](https://github.com/kpdecker/jsdiff/compare/7.0.0...v8.0.3)

---
updated-dependencies:
- dependency-name: diff
  dependency-version: 8.0.3
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: diff
  dependency-version: 8.0.3
  dependency-type: direct:production
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-15 11:22:54 +01:00
f000b00c65 Server Events: Add runtime state check and error handling to ServerEventRouter (#21406)
Add resilience to ServerEventRouter to prevent failures during unattended
install/upgrade when SignalR (especially Azure SignalR) is configured.

Changes:
- Skip server event routing when runtime level is not Run (Install/Upgrade)
- Add try-catch with warning logging for graceful degradation on SignalR failures
- Add backwards-compatible obsolete constructor using StaticServiceProvider pattern
- Add unit tests for runtime level checks

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 10:20:06 +00:00
Andy Butland 8ac46e99b7 Applied naming suggestions made in review of #21374. 2026-01-15 07:51:34 +01:00
Andy Butland 59cc153b84 Merge branch 'main' into v18/dev 2026-01-15 07:46:41 +01:00
Chris HoustonandGitHub 720774d219 Code Quality: Fix CS1574 and CS0419 XML documentation warnings (#21400)
Docs: Fix CS1574 and CS0419 XML documentation warnings

Fixed 17 build warnings related to XML documentation cref attributes:

CS1574 (cref attribute could not be resolved):
- IApiMediaQueryService: Changed see cref to paramref for path parameter
- Permission resources: Removed cross-assembly cref to handlers in Management API
- ContentService: Removed reference to non-existent SaveAndPublish method
- ModelsBuilderModeValidator: Fixed cref to Constants.ModelsBuilder.ModelsModes.Nothing
- ImageCropperPropertyValueEditor: Fixed cref to TemporaryFileUploadValueBase.Src
- NPocoSqlServerDatabaseExtensions: Removed cref to external NPoco method
- RegisteredReloadableLogger: Removed cref to non-existent RefreshingRazorViewEngine
- FriendlyPublishedContentExtensions: Removed cref to non-existent AncestorOrSelf methods
- ManagementApiControllerBase: Removed cref to inherited Forbid() method
- BackOfficeExternalLoginProviderErrorMiddleware: Fixed namespace in cref
- HasScheduleFlagProvider: Fixed typo HasScheduleSignProvider -> HasScheduleFlagProvider

CS0419 (ambiguous cref reference):
- ServiceCollectionExtensions: Specified exact overload ConfigureUmbracoDefaults(IHostBuilder)
- IUserStartNodeEntitiesService: Replaced ambiguous GetPagedChildren cref with plain text
2026-01-15 06:45:13 +01:00
Chris HoustonandGitHub e389e3c505 Removing a variable that is not being used - fixes warning CS0168 (#21398) 2026-01-15 06:30:52 +01:00
9bf54ca9cb UI: Refactor breadcrumb URLs to use Path Constants (#21179)
- Add UMB_WORKSPACE_EDIT_PATH_PATTERN and UMB_WORKSPACE_EDIT_VARIANT_PATH_PATTERN
  to core workspace paths for generic edit URL generation
- Fix UmbPathPattern to support multi-level chaining via toAbsolutePatternString()
- Refactor workspace-menu-breadcrumb to use new path patterns
- Refactor menu-variant-tree-structure-workspace-context-base to use new patterns
- Refactor tree-item-context-base to use UMB_WORKSPACE_EDIT_PATH_PATTERN
- Refactor user-grid-collection-view to use existing UMB_EDIT_USER_WORKSPACE_PATH_PATTERN
- Remove outdated TODO about encoding uniques (handled at data source)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-01-14 11:08:49 +01:00
59675a083d Code Quality: Fix StyleCop warnings SA1116, SA1401, SA1649, SA1405, SA1121, SA1130, SA1306, SA1028, SA1400, SA1106 (#21377)
* fix(stylecop): resolve SA1106 - remove empty statement

* fix(stylecop): resolve SA1400 - add missing access modifiers

* fix(stylecop): resolve SA1028 - remove trailing whitespace

* fix(stylecop): resolve SA1306 - rename fields to lowercase

* fix(stylecop): resolve SA1130 - use lambda syntax

* fix(stylecop): resolve SA1121 - use built-in type aliases

* fix(stylecop): resolve SA1405 - add messages to Debug.Assert calls

* fix(stylecop): resolve SA1649 - rename files to match type names (partial)

* fix(stylecop): resolve SA1401 - convert fields to const/readonly (partial)

* fix(stylecop): resolve SA1116 - reformat multi-line parameters (partial)

* fix(stylecop): revert breaking changes, add V18 TODO comments

* fix: correct TODO comment for SA1306 - should rename to _completed

* Standardize API file names across modules - No code changes, file names.

- Extracts login model to a dedicated file and preserves binding behavior
- Renames multiple API files to align with updated conventions ( Just to match their names in the code, not changing the actual API names, i.e. no breaking changes )
- Updates DI extensions, mappings, and OpenAPI helpers to follow new naming
- Adjusts tests for consistent formatting and readability
- Preserves behavior; no logic changes, references kept intact

* fix(tests): refactor UserEmail to virtual property pattern

- Convert protected field _userEmail to virtual property UserEmail
- Remove dead code (_userEmail += "groupName" executed after request)
- Update derived test classes to use property instead of field
- Maintains original name to avoid breaking changes
- Follows best practice: virtual property allows derived class override

This was originally changed in my PR from UserEmail to _userEmail, so changing it back to ensure no breaking change, even though this is in a test class.

* Committing small fix to prevent a breaking change, adding commit for future removal.

* Renames helper class and removes BOM

Renames internal helper to follow naming conventions without the T prefix
Removes stray BOM from header to ensure clean compilation
No runtime behavior changes

* Split Physical FileSystem interface into it's own file.

* Split the IContentQueryService into it's own file

Also updated XML docs.

* Reverting the package-lock.json

* Updated the typo for Permision -> Permission

Updated the file name and class to: AddUserGroup2PermissionTable

This should be safe to do so as migrations are logged with their GUID's not the class names.

* Update src/Umbraco.Core/Scoping/CoreScope.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Reverting a binary change.

* Reverted rename of public migration class.

* Revert name in migration plan.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-14 09:17:47 +00:00
Sebastiaan JanssenandGitHub a4a6c37c8b Only run this scheduled job on the original repo, not on forks 2026-01-14 10:01:23 +01:00
Andreas ZerbstandGitHub 396a8edd91 E2E: QA updated test helpers to fix flaky acceptance tests (#21373)
* Bumped helpers

* Updated tests

* Bumped version

* Bumped version again to fix flaky renaming test
2026-01-14 08:58:05 +01:00
Andy ButlandandGitHub de87a71bc8 Migrations: Ensure description column is added before earlier User Group migration runs (#21378)
* Ensure the description field added in a later migration for user groups is available when the earlier migration on this table runs.

* Update implementation of fix to store and use the state of UserGroupDto at the time of migrations.
2026-01-14 07:59:39 +01:00
29ecae7010 Entities: Prevent changing Key property on existing entities (#21374)
* Prevent setting of entity Key to a new value for already persisted entities.

* Handled file based entities that have a key dependent on their path, so need to be able to have the key changed on move.

* Fixed package data update of content type to resolve failing integration test.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2026-01-14 06:45:11 +00:00
abe772b963 Collection: Introduce Collection Text Filter Extension (#21172)
* scaffolding of a collection text filter extension

* Refactor collection text filter to use API interface

* Fix incorrect tag

* Update types.ts

* Update collection-text-filter.extension.ts

* Add cancelation to debounced search on destroy

* clean up

* add js docs

* two way binding of filter value

* clean up

* Add collection text filter manifest example

Introduced a new filter manifest for the example collection and updated the main manifests file to include it. This enables a text filter extension for the example collection.

* Delete unused element and context

* Update src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/user-group-collection.context-token.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update user-group-table-collection-view.element.ts

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-13 20:56:27 +01:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>nielslyngsoeNiels Lyngsø
3342d31270 Add loading indicator and error handling to Member Public Access Modal (#21087)
* Initial plan

* Add loading indicator and error handling to public access modal

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Fix test for public access modal element

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-01-13 14:24:09 +00:00
Niels LyngsøandGitHub 7557f7bfa5 Content Type Designer: make inherited property appear more like the local, to take less focus (#21229)
make inherited property appear more like the local, otherwise it takes too much attention.
2026-01-13 13:40:54 +00:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>nielslyngsoeNiels Lyngsø
dc459bca67 Add loading indicator to composition picker modal (#21086)
* Initial plan

* Add loading indicator to composition picker modal

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Document implementation and verify changes

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Address code review feedback - add accessibility and documentation

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-01-13 13:14:40 +00:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>nielslyngsoeMads Rasmussen
2a7478e7f4 Add loading indicator to data type picker flow modal (#21085)
* Initial plan

* Add loading indicator to data-type-picker-flow-modal

- Added _isLoading state variable
- Updated #getDataTypes() to set loading state with try-finally
- Added uui-loader component in #renderGrid() when loading
- Created test file with basic tests
- Fixed linter warnings

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Refactor: Replace inline styles with CSS class for loader

- Added .loader-container CSS class
- Removed inline styles from loader div
- Improves maintainability and follows best practices

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Improve tests and revert unrelated package-lock.json changes

- Test observable behavior (loader element) instead of private properties
- Added tests for loader visibility during loading states
- Added test for loader removal after loading completes
- Reverted unintended changes to Umbraco.Web.UI.Login/package-lock.json

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Refactor: Extract helper function in tests for cleaner code

- Added setLoadingState helper function to reduce code duplication
- Updated comments to reflect testing reactive state property
- Improved test readability and maintainability

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* delete test file not testing anything

* show loading indicator in search field instead

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-01-13 13:05:59 +00:00
Niels LyngsøandGitHub 7b5a087ea5 Sidebar: Make scale grab-area smaller (#21228)
make split view scale area smaller
2026-01-13 13:57:54 +01:00
Andy ButlandandGitHub fefb9ca7aa Docs: Add branch naming convention details to CLAUDE.md (#21311)
* Update Claude memory files to provide further instruction on branch naming convention.

* Resolved points raised in code review.
2026-01-13 13:50:15 +01:00
Andy ButlandandGitHub 8f584e1a49 Tests: Fix intermittent failure in RecycleBinMediaProtectionHelperTests (#21332)
Use thread-safe collections in unit tests verifying functionality that uses parallel processing.
2026-01-13 10:20:35 +01:00
Laura Neto 409f5072af Merge branch 'main' into v18/dev 2026-01-13 10:09:56 +01:00
Andy ButlandandGitHub 58a0b160b2 Umbraco Helper: Align GetDictionaryValue nullability with behaviour (#21372)
Align GetDictionaryValue nullability with behaviour (returns empty string when no dictionary item is found for the provided key).
2026-01-13 06:42:17 +01:00
de02456cf8 E2E: QA Added acceptance tests for removing not-found items (#21371)
* Added tests for removing a not-found member picker

* Added tests for adding thumbnail to block

* Updated tests to match the test helper changes

* Refactor code to avoid duplication

* Added tests for removing a thumbnail from a block list/grid and refactor code

* Bumped version

* Bumped version and make tests run in the pipeline

* Update smokeTest command to use '@smoke' filter

---------

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-01-13 03:57:04 +00:00
f47a456515 Datatype Collection: Add fallback icon for datatype (#21269)
Add fallback icon for datatype

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-01-12 15:22:41 +01:00
engjlr 234907aedb Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-01-12 13:57:57 +01:00
CopilotJacob Overgaardcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>nielslyngsoeNiels LyngsøEngiber Lozadaengjlr
e3ff3ea3b9 Add loader and error handling to MFA modal (#21089)
* Initial plan

* Add loader and error handling to MFA modal

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Use localized error messages in MFA modal

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Refactor render logic into separate #renderContent method

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

* Revert src/Umbraco.Web.UI.Login/package-lock.json to main branch version

* Removed unused variable.

* Center the loader in MFA modal.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>
2026-01-12 13:51:59 +01:00
Andy Butland c8ba79b2d1 Merge branch 'main' into v18/dev 2026-01-12 11:54:52 +01:00
Jacob OvergaardandClaude Sonnet 4.5 6050bdd40f Tree pickers: Implement noAccess property UI handling for user start nodes
- Add noAccess observable to document and media tree item contexts
- Add visual styling (grayed out, italic, cursor: not-allowed) for noAccess items in tree views
- Implement click prevention to block navigation when noAccess is true
- Update document and media picker input contexts with type-safe guards to prevent selection of noAccess items
- Create type guard utilities (isDocumentTreeItem, isMediaTreeItem) in separate utils files
- Items with noAccess are shown for navigation but cannot be selected or opened

This implements Task 63363 for Feature 63060 "Handle Start Nodes"

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-12 10:52:10 +01:00
8c23cb2ffd Block Grid: Resolve translation keys for group names (closes #20696) (#21362)
* Block Grid: Resolve translation keys for group names (closes #20696)

Add localization support for block group names in two locations:
- Block Grid area type permission combobox options
- Block catalogue modal group headers

Translation keys (e.g., #content_isPublished) used as group names
are now properly resolved instead of displaying the raw key.

* fix: moves group.name to mapper so search works

* fix: localizes block types in permissions element too

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-12 08:16:08 +00:00
faba205025 Collections: fix create action causing full page navigation (#21366)
Fix collection create action causing full page navigation instead of SPA routing

When a collection create action had an href, clicking it would trigger a full
browser navigation instead of using history.pushState for SPA routing. This was
caused by event.stopPropagation() being called before the early return when an
href was present, preventing the global ensureAnchorHistory() listener from
intercepting the click event.

The fix moves stopPropagation() to only execute when we're actually handling
the click via execute() (no href), allowing href-based navigation to bubble
to the window-level router listener for proper SPA navigation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-12 07:55:55 +01:00
Chris HoustonandGitHub 35c940364c Code Quality: Fix SA1500, SA1111 and SA1134 StyleCop warnings (#21369)
style: fix SA1500, SA1111, SA1134 StyleCop warnings

Fixed 194 StyleCop analyzer warnings across the codebase:

- SA1500: Move opening braces to their own line for multi-line statements (80 warnings)
- SA1111: Move closing parenthesis to same line as last parameter (50 warnings)
- SA1134: Place each attribute on its own line (64 warnings)

Also added XML documentation to any public APIs within the edited files.
2026-01-12 07:06:56 +01:00
Andy ButlandandGitHub f4ff1da043 Cache: Resolve thread safety issues in RepositoryCacheKeys and FullDataSetRepositoryCachePolicy (closes #21350) (#21355)
* Verify and resolve thread safety issues in RepositoryCacheKeys.

* Verify and resolve thread safety issues in FullDataSetRepositoryCachePolicy.
2026-01-12 06:58:13 +01:00
Niels Lyngsø 30aea87e28 correct comments 2026-01-09 21:33:01 +01:00
Niels LyngsøandGitHub 93229fd457 Mobile navigation: enable horizontal scroll on small screens (#21354)
* make backoffice minimum 800px wide

* minimum 920px
2026-01-09 14:19:47 +00:00
4f29bcd8d6 Fix #20769, added support for clip-text for UmbTableColumn (#20808)
Co-authored-by: Markus Johansson <markus@obviuse.se>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
2026-01-09 13:26:42 +00:00
ef1b48c992 Obsolete Code: Remove obsolete methods and constants relating to allowed application and start node claims (#20124)
* Delete GetStartContentNodes

* Delete GetStartMediaNodes

* Delete GetAllowedApplications

* Delete ClaimTypes

* Update protected recycle bin functionality to no longer used removed claim details.  Added unit tests to verify behaviour.

* Fixed failing unit tests now the number of claims included is reduced.
Addressed comments from code review.

* Minor code tidy.

* Expose claim necessary for retrieving the user key.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-09 12:25:33 +00:00
Niels LyngsøandGitHub 80dddc430c declare events in the global event interface map (#21349) 2026-01-09 13:12:41 +01:00
Andy Butland e9819d6e57 Merge branch 'main' into v18/dev 2026-01-09 12:23:44 +01:00
5a33a55f21 Block workspace: Enforce "AllowEditInvariantFromNonDefault" in variant blocks (closes #20633) (#20868)
* implement preventEditInvariantFromNonDefault for variant blocks

* remove unused

* refactor to enforce both document and block case from the document module

* remove implementation from doc workspace

* prevent editing invariant blocks from non default

* remove unused imports

* more explicit class names

* Refactor invariant edit guard rule creation

Extracted the creation of the invariant property edit guard rule into a reusable _createRule method in the controller base class. Updated block and document workspace controllers to use this method

* Refactor invariant edit rule logic into base controller

Moved the logic for observing properties and variant options and applying property guard rules into a new _observeAndApplyRule method in the base controller. Updated document block and workspace controllers to use this shared method, reducing code duplication and improving maintainability.

* Refactor invariant block edit check into helper methods

Extracted logic for checking invariant blocks and default language datasets into private async methods for better readability and maintainability. This refactor also corrects a context check typo and improves error handling.

* remove unused

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2026-01-09 09:51:05 +00:00
Mads RasmussenandGitHub 4276e903d7 Fix MSW typescript compile errors (#21319)
Refactor mock handlers to use typed request/response models
2026-01-09 08:50:16 +01:00
Andy ButlandandGitHub c5098f6df3 Multi-node picker: Validate content type when filter is configured but object type is not (closes #21338) (#21342)
Validate content type for multi-node picker when content types are defined but the object type is not (consider as being for a document).
2026-01-09 06:48:42 +01:00
aa0d636503 Entity Signs: rounded infobox top corners (#21341)
* correct styling for entity sign infobox top corners

* Used shorthand notation for padding.

---------

Co-authored-by: engjlr <enl@umbraco.dk>
2026-01-08 17:47:14 +00:00
aka James4uandGitHub a0e1908d2b fix(slider): enforce Maximum Value configuration (closes #21323) (#21339)
- Fixed inverted logic in #parseNumber method
- Changed Number.isFinite(num) ? undefined : num to Number.isFinite(num) ? num : undefined
- Previously, valid max values (e.g., 50) were being ignored and defaulting to 100
- Now correctly parses and uses the configured Maximum Value from data type settings

This ensures the Maximum Value setting in Slider datatype configuration
is properly enforced in the slider UI component.
2026-01-08 17:49:12 +01:00
3e57bb8128 Multi-link picker: Allow drag and drop into empty link picker (closes #21295) (#21325)
* fix(backoffice): allow drag and drop into empty link picker (closes #21295)

* refactor: use classMap to avoid empty class attribute

* refactor: use margin/padding trick for drop zone

* refactor: use CSS :has() selector instead of class

* also enable it for the Document input

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2026-01-08 15:24:42 +01:00
Dirk SeefeldandGitHub 0094c19780 Gitignore: Exclude acceptance test results from git (#21336)
* exclude acceptance test results from git

* reorder .gitignore
2026-01-08 13:01:03 +00:00
Andy ButlandandGitHub ed162feddf Server Events: Route document updated event when public access entries are modified (closes #21237) (#21310)
* Route server events for public access updates to indicate an update to the protected document.

* Add unit tests for all ServerEventSender notification handlers.

* Adds additional test recommended in code review.

* Addressed parameter name issue raised in code review.
2026-01-08 09:31:27 +01:00
Andreas ZerbstandGitHub 28e9607910 QA: E2E skip running sqlite acceptance test on nightly pipeline (#21331)
* Added skip condition for SQLite

* Added missing comma

* Added missing bracket

* Followed naming convention of parameters and added comments
2026-01-08 08:32:02 +01:00
Andy Butland b8d02067fe Merge branch 'release/17.1'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2026-01-08 06:36:50 +01:00
3fd311bce8 E2E: QA added temporary waits to flaky acceptance (#21324)
* Added wait

* Additional fixes

* More fixes

---------

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2026-01-08 03:13:54 +00:00
calmandGitHub 55b77157ec Backoffice entity actions: prevent entity actions dropdown from closing on first click (#21322)
fix(backoffice): prevent entity actions dropdown from closing on first open (closes #21320)
2026-01-07 17:04:12 +01:00
calmandAndreas Zerbst 2832436a0e Fix login validation messages not showing on submit (#21306)
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
(cherry picked from commit 4df4ee9c31)
2026-01-07 16:06:51 +01:00
906cbb50d8 Removed margin-top to address the loader icon shifting when entering … (#21301)
* Removed margin-top to address the loader icon shifting when entering text

* Space

---------

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-01-07 13:39:08 +00:00
Engiber LozadaandGitHub 93dff1a7a3 Entity Sings: Add localization keys to core entity signs. (#21302)
Improving localization support for core entity signs.
2026-01-07 14:26:31 +01:00
Niels Lyngsø 962db17628 lint fixes 2026-01-07 13:36:57 +01:00
4df4ee9c31 Fix login validation messages not showing on submit (#21306)
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-01-07 13:34:57 +01:00
Andreas ZerbstandGitHub c37fab8e4e E2E: QA Update acceptance to use new assertion pattern (#21297)
* Updated tests

* Updated culture

* Updated tests to use new assertion helpers

* Updated helpers

* Updated tests

* Updated tests

* Updated tests

* Bumped version

* Bumped version
2026-01-07 12:19:02 +00:00
bfc8053c11 Docker: Fix Docker template healthcheck, bind mounts, and HTTPS support (fixes #21278) (#21299)
* Fix test entrypoint

* Fix healthcheck.sh

* Ensure bind mounts gets created on host

* Fix bind mounts permission issues

* Generate self signed cert for dev

* Only generate cert for localhost

* Fixup docker compose file

* Update templates/UmbracoProject/entrypoint.sh

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update templates/UmbracoProject/Dockerfile

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix APP_UID runtime availability and optimize chown performance

- Export APP_UID as ENV so it's available at container runtime
  (ARG values from .NET base image are only available at build time)
- Only run chown -R when directory ownership differs from APP_UID
  to avoid slow recursive operations on large directories

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 12:56:58 +01:00
Andy ButlandandGitHub 462d63b055 Media: Fix files not deleted from disk when recycle bin protection is enabled (#21309)
* Fix bug where with recycle bin media protection on, the files on disk aren't deleted when the recycle bin is emptied.

* Fix display of media URL when in recycle bin and protection of trashed media is enabled.
2026-01-07 11:20:09 +00:00
50b2c8e03b Performance: Only flush ID/Key map in ContentCacheRefresher on content deletion (#21283)
* Clean-up of ContentCacheRefresher: resolved warnings and tidied up code and comments.

* Only flush the ID/Key map when content is deleted.

* Update src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-07 12:14:36 +01:00
Andy Butland 2564d04941 Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2026-01-07 11:40:47 +01:00
Andy Butland ca3091e92e Fixed version of Microsoft.Extensions.Caching.Hybrid from incorrect one added in earlier commit. 2026-01-07 11:40:33 +01:00
Niels Lyngsø 036225a76d early return if manager is not present 2026-01-07 11:39:49 +01:00
307f3be505 User group: add description to user group (discussions/14986) (#21057)
* Adding description to user groups

* Add description to dto and test and umbraco plan

* update unit test for user group

* remove change from link picker

* edit icon ui for user group

* Fixed table exists check in migration.

* update description in table user groups

* update user group editor css

* update description default

* remove description column element

* add ignore large method

* remove codesence

* update user group descriptions default

* Added description to constructor of ReadOnlyUserGroup.

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2026-01-07 11:17:04 +01:00
Niels LyngsøandNiels Lyngsø b5fb17682c Hotfix: refactor of #21221 (#21293)
* refactor reload method to entity-detail

* refactor property value transfering when variation changes
2026-01-07 10:53:11 +01:00
Andy ButlandandNiels Lyngsø 83882a94bd Bumped version to 17.1.0.
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2026-01-07 10:53:11 +01:00
0c5156c7b3 Content: Fix property variation change breaking document save via Infinite Editing (closes #21195) (#21221)
When changing a property's variation setting (Shared/Invariant ↔ Variant) via Infinite Editing,
the document would fail to save with a 404 error.

This fix:
- Adds value migration fallback logic in UmbPropertyValuePresetVariantBuilderController
  to find values when culture/segment doesn't match exactly
- Overrides reload() in UmbContentDetailWorkspaceContextBase to process incoming data
  through _processIncomingData() for proper value transformation
- Detects property variation changes and triggers document reload to migrate values

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 10:52:52 +01:00
Kenn JacobsenandGitHub c859b2883d Members: Fix IMemberService.GetByKeysAsync() (#21312)
Fix IMemberService.GetByKeysAsync()
2026-01-07 07:54:20 +00:00
2aa49a3004 Performance: Avoid database lookup in UserIdKeyResolver for super-user (#21281)
* Avoid an unnecessary look-up for the super-user when resolving ID from key and vice versa.
Utilise an async database methods given the enclosing method is async.

* Applied suggestions from code review.

* Revered async amend (caused pipeline failures with integration tests).

* Apply suggestions from code review

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

---------

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2026-01-07 08:37:59 +01:00
Andy ButlandandGitHub 54a1364a88 Dependencies: Update Microsoft packages to 10.0.1 and pin vulnerable transitive dependencies (closes #21122) (#21285)
* Added transitive dependency references to specific libraries where direct dependencies depend on vulnerable versions.

* Enable CentralPackageTransitivePinningEnabled.

* Update MS dependencies to 10.0.1 patch versions.

* Removed System.Text.Encodings.Web.

* Add TODOs for pinned dependency removal.
2026-01-07 06:58:12 +00:00
603788a039 Extension insights: Hide icon from table collection (#21268)
Hide icon from table collection

Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-01-06 15:00:24 +00:00
dependabot[bot]andJacob Overgaard c8454684d0 Bump qs
Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client directory: [qs](https://github.com/ljharb/qs).


Updates `qs` from 6.14.0 to 6.14.1
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.0...v6.14.1)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-06 15:46:22 +01:00
Niels LyngsøandGitHub 21736159af Hotfix: refactor of #21221 (#21293)
* refactor reload method to entity-detail

* refactor property value transfering when variation changes
2026-01-06 15:45:33 +01:00
Laura Neto 480a208655 Merge branch 'main' into v18/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2026-01-06 14:52:30 +01:00
848df27482 Auto close focus leave (#20700)
* working on a auto closing ... modal when focus leaves

* remove appsetting for local development

* rewrites the focus function to check if the shadow dom exsits before trying to set focus

* Fix JSON formatting in appsettings.Development.template.json

* Simplify focus logic in entity action list

Refactored the focus method to directly focus the first menu item after it is rendered, removing unnecessary nested updateComplete checks and focusing logic for the label button.

* Remove unused 'nothing' import and minor formatting

* Call ext.component?.focus() instead of chaining updateComplete promises.

* Update entity-action-list.element.ts

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>
2026-01-06 13:43:25 +00:00
6ed4075eeb Added localize label for entity sign bundle (#21252)
* Added localize for entity sign bundle label

* Updated how entity-sign-bundle.element handles label localize

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Removed unnecessary conditional check for localize entity-sign-bundle

* Moved localize into render method for entity-sign-bundle.element

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2026-01-06 14:00:48 +01:00
0da1fa116e Markdown Conversion: Remove hard dependency on deprecated library and replace with IMarkdownToHtmlConverter abstraction (closes #21238 and #19500) (#21242)
* Add IMarkdownToHtmlConverter abstraction with Markdig and HeyRed implementations

- Add IMarkdownToHtmlConverter interface in Umbraco.Core.Strings
- Add MarkdigMarkdownToHtmlConverter using the Markdig library (new default)
- Add HeyRedMarkdownToHtmlConverter using HeyRed.MarkdownSharp (deprecated, for backwards compatibility)
- Update HealthChecks.MarkdownToHtmlConverter to use the new abstraction
- Update MarkdownEditorValueConverter to use the new abstraction
- Add unit tests for both markdown converter implementations
- Add unit tests for HealthChecks.MarkdownToHtmlConverter syntax highlighting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from code review.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-06 08:43:47 +01:00
Andy Butland 4e2fdfc269 Bumped version to 17.1.0. 2026-01-06 07:52:42 +01:00
Nhu DinhandGitHub 51cec0e41f E2E: QA Updated acceptance tests for max length validation message (#21230)
* Updated max length validation message

* Fixed format
2026-01-05 17:26:14 +07:00
b563561d2a Management API: Scope notification headers and add document inclusion abstraction (closes #21231, #21241 and #21240) (#21244)
* Adds a check to ensure notifications are only added to relevant CMS management API endpoints.

* Add null check for tagging actions to handle null management API GroupName.

* Provide abstraction for the DocInclusionPredicate when configuring SwaggerGenOptions.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-05 11:16:41 +01:00
c003751466 Content Type Cache: Clear ContentTypeCommonRepository cache when data types change (closes #21261) (#21289)
Cache: Clear ContentTypeCommonRepository cache when data types change

When a data type's EditorAlias is changed (e.g., BlockList to SingleBlock), the ContentTypeCommonRepository 5-minute cache was not being cleared. This caused content types to return stale PropertyEditorAlias values until server restart, leading to validation using the wrong property editor validators.

The fix adds IContentTypeCommonRepository as a dependency to DataTypeCacheRefresher and calls ClearCache() in RefreshInternal(), matching the pattern already used in ContentTypeCacheRefresher and TemplateCacheRefresher.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 18:02:36 +09:00
caa01b5122 Code quality: resolve build warnings CS0169 and CS0649 (#21258)
* Fixed the 22 warnings.

Also updated the XML documentation where required.

* Updating XML docs.

* Noted version in obsoletion message.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2026-01-04 11:52:25 +00:00
Chris HoustonandGitHub b14a7ca3e3 Code Quality: Fix ASP0019 warnings by replacing Headers.Add with Headers.Append (#21260)
Use Append for response headers

- Replaces Add with Append when adding response headers to conform to IHeaderDictionary usage.
- Applies across unauthorized handling, redirects, and custom header signaling.
- Updates tests to use Append consistently.
- Removes ASP0019 from warnings in project configs to reflect new approach.
2025-12-31 12:00:15 +01:00
Chris HoustonandGitHub 0803ab8bda Build Warnings: Suppress ASPDEPR003 warnings in DevelopmentMode.Backoffice (#21259)
Silences deprecation warning in dev mode

Silences deprecated runtime-compile warning in dev mode
Keeps development-time runtime compilation enabled for in-memory dev setup
Relates to ASPDEPR003
2025-12-31 11:29:55 +01:00
Nhu DinhandGitHub ac86d97c4e E2E: QA Update acceptance tests to use refactored UI helpers (#21266)
* Bumped version

* Updated tests to match new changes

* Bumped version

* Bumped version

* Use isSuccessNotificationVisible instead of doesSuccessNotificationHaveText

* Updated tests to avoid flaky tests

* Bumped version of test helper

* Bumped version of test helper

* Bumped version

* Bumped version

* Bumped version

* Update waits to avoid hardcoded values
2025-12-31 14:47:53 +07:00
cbde6af9c0 Code quality: Fixing XML docs issues CS1570, CS1572, CS1723, & CS1575 (#21256)
* FIxing XML docs issues CS1570, CS1572, CS1723, & CS1575

* Update ContentImagingSettings.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update ITypedSingleBlockListProcessor.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update PublishedContentExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-26 10:57:16 +01:00
Chris HoustonandGitHub da8a532080 Code quality: Remove obsolete serialization constructors (fixing SYSLIB0051 warnings) (#21235)
* fix(SYSLIB0051): Remove obsolete serialization constructors

Removes obsolete formatter-based serialization constructors from exception
classes to resolve SYSLIB0051 warnings. This is NOT a breaking change as:

- Binary serialization is deprecated in modern .NET
- No BinaryFormatter usage exists in the codebase
- Microsoft recommends removing these obsolete constructors

Affected files:
- AuthorizationException.cs
- BootFailedException.cs
- ConfigurationException.cs
- PanicException.cs
- UnattendedInstallException.cs
- RetryLimitExceededException.cs
- IncompleteMigrationExpressionException.cs
- HttpUmbracoFormRouteStringException.cs
- ModelBindingException.cs

Also removes SYSLIB0051 from WarningsNotAsErrors in project files.

* fix(SYSLIB0051): Mark obsolete serialization constructors for removal in v19
2025-12-24 15:46:29 +01:00
cf7623e5bd Code quality: Resolve CS0108 compiler warnings by adding explicit 'new' keyword (#21236)
* fix: Resolve CS0108 compiler warnings by adding explicit 'new' keyword

fix: Resolve CS0108 compiler warnings by adding explicit 'new' keyword to hiding members

- Add 'new' modifier to Empty properties in BlockGridModel, BlockListModel, RichTextBlockModel
- Add 'new' modifier to DeepCloneWithResetIdentities in IContentType, IMediaType
- Add 'new' modifier to Save/GetById methods in IContentService, IMediaService, IMemberService
- Add 'new' modifier to EFCore interface members (IAmbientEFCoreScopeStack, IEFCoreScope)
- Add 'new' modifier to ExternalLoginSignInResult.NotAllowed and CreateMediaTypeRequestModel.Collection
- Improve XML documentation for edited public members

Note: CS0114 warnings (virtual/override) were intentionally not fixed as they may be breaking changes. Will add more details to the PR.

* fix: Resolve CS0108 compiler warnings by adding explicit 'new' keyword

fix: Resolve CS0108 compiler warnings by adding explicit 'new' keyword to hiding members

- Add 'new' modifier to Empty properties in BlockGridModel, BlockListModel, RichTextBlockModel
- Add 'new' modifier to DeepCloneWithResetIdentities in IContentType, IMediaType
- Add 'new' modifier to Save/GetById methods in IContentService, IMediaService, IMemberService
- Add 'new' modifier to EFCore interface members (IAmbientEFCoreScopeStack, IEFCoreScope)
- Add 'new' modifier to ExternalLoginSignInResult.NotAllowed and CreateMediaTypeRequestModel.Collection
- Improve XML documentation for edited public members

Note: CS0114 warnings (virtual/override) were intentionally not fixed as they may be breaking changes. Will add more details to the PR.

* Modifying the PR based on feedback from Andy.

Files Modified (Removed Duplicate Members)
src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CreateMediaTypeRequestModel.cs
Removed duplicate Collection property (already defined in base class ContentTypeModelBase)
src/Umbraco.Core/Services/IContentService.cs
Removed duplicate GetById(Guid key) method (already in IContentServiceBase<IContent>)
Removed duplicate Save(IEnumerable<IContent> contents, ...) method (already in IContentServiceBase<IContent>)
src/Umbraco.Core/Services/IMediaService.cs
Removed duplicate GetById(Guid key) method (already in IContentServiceBase<IMedia>)
Removed duplicate Save(IEnumerable<IMedia> medias, ...) method (already in IContentServiceBase<IMedia>)
src/Umbraco.Core/Services/IMemberService.cs
Removed duplicate Save(IEnumerable<IMember> members, ...) method (already in IContentServiceBase<IMember>)
Files Left Unchanged (Keeping new keyword)
The following files were correctly fixed with the new keyword because they intentionally hide base members to return more specific types:
BlockGridModel.cs, BlockListModel.cs, RichTextBlockModel.cs - Empty returns specific type
IContentType.cs, IMediaType.cs - DeepCloneWithResetIdentities returns specific interface
ExternalLoginSignInResult.cs - NotAllowed returns ExternalLoginSignInResult instead of SignInResult
IEFCoreScope.cs, IAmbientEfCoreScopeStack.cs - re-declarations for documentation purposes

* fix: Resolve CS0108 compiler warnings by adding explicit 'new' keyword

fix: Resolve CS0108 compiler warnings by adding explicit 'new' keyword to hiding members

- Add 'new' modifier to Empty properties in BlockGridModel, BlockListModel, RichTextBlockModel
- Add 'new' modifier to DeepCloneWithResetIdentities in IContentType, IMediaType
- Add 'new' modifier to Save/GetById methods in IContentService, IMediaService, IMemberService
- Add 'new' modifier to EFCore interface members (IAmbientEFCoreScopeStack, IEFCoreScope)
- Add 'new' modifier to ExternalLoginSignInResult.NotAllowed and CreateMediaTypeRequestModel.Collection
- Improve XML documentation for edited public members

Note: CS0114 warnings (virtual/override) were intentionally not fixed as they may be breaking changes. Will add more details to the PR.

* Modifying the PR based on feedback from Andy.

Files Modified (Removed Duplicate Members)
src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CreateMediaTypeRequestModel.cs
Removed duplicate Collection property (already defined in base class ContentTypeModelBase)
src/Umbraco.Core/Services/IContentService.cs
Removed duplicate GetById(Guid key) method (already in IContentServiceBase<IContent>)
Removed duplicate Save(IEnumerable<IContent> contents, ...) method (already in IContentServiceBase<IContent>)
src/Umbraco.Core/Services/IMediaService.cs
Removed duplicate GetById(Guid key) method (already in IContentServiceBase<IMedia>)
Removed duplicate Save(IEnumerable<IMedia> medias, ...) method (already in IContentServiceBase<IMedia>)
src/Umbraco.Core/Services/IMemberService.cs
Removed duplicate Save(IEnumerable<IMember> members, ...) method (already in IContentServiceBase<IMember>)
Files Left Unchanged (Keeping new keyword)
The following files were correctly fixed with the new keyword because they intentionally hide base members to return more specific types:
BlockGridModel.cs, BlockListModel.cs, RichTextBlockModel.cs - Empty returns specific type
IContentType.cs, IMediaType.cs - DeepCloneWithResetIdentities returns specific interface
ExternalLoginSignInResult.cs - NotAllowed returns ExternalLoginSignInResult instead of SignInResult
IEFCoreScope.cs, IAmbientEfCoreScopeStack.cs - re-declarations for documentation purposes

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Reverted the one of the changes and updated some XML doc tags.

* Should have committed these files.

Corrected a name space in the test files.

* Remove warning on missing access modifiers on interface members.

* Revert breaking namespace change.

* Fixed build errors following namespace reversion.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-24 13:11:03 +01:00
8a47072b9b Code quality: Replace obsolete APIs in Umbraco.TestData controllers (#21251)
* fix(tests): Replace obsolete APIs in Umbraco.TestData controllers

Replaced deprecated synchronous service methods with their modern async
equivalents in the TestData controllers to eliminate CS0618 warnings.

Changes:
- LoadTestController: Replace IFileService with ITemplateService,
  use IDataTypeService.GetAsync(Guid) instead of GetDataType(int),
  use IContentTypeService.CreateAsync() instead of Save()
- SegmentTestController: Use IContentTypeService.UpdateAsync()
  instead of Save()
- UmbracoTestDataController: Use IContentTypeService.CreateAsync()
  and UpdateAsync() instead of Save()

Also adds comprehensive XML documentation to all three controllers
including class summaries, constructor parameters, and method
documentation.

The controllers now use:
- Constants.DataTypes.Guids.TextstringGuid instead of magic int -88
- Constants.Security.SuperUserKey for async service operations
- Task<IActionResult> return types where async operations are used

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Further amends from code review.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-24 09:36:45 +00:00
Chris HoustonandGitHub 6726e6b208 Benchmarks: Fix obsolete BenchmarkDotNet API warnings by replacing depreciated function calls. (#21250)
* fix(benchmarks): resolve obsolete BenchmarkDotNet API warnings

Update BenchmarkDotNet configuration to use current API methods:

- Replace deprecated `ManualConfig.Add()` with `AddDiagnoser()` for memory diagnostics
- Replace deprecated `ConfigExtensions.With()` with `AddJob()` for job configuration
- Initialize `_totalItemCount` field to suppress CS0649 warning

These changes resolve 4 compiler warnings (CS0618, CS0649) in the benchmark project
without any functional changes.

* Removing the benchmark artifacts and adding the folder to gitignore
2025-12-24 10:25:35 +01:00
27209c2295 Code documentation: Added XML Docs to the files in the Umbraco.Cms.Imaging.ImageSharp2 project (#21249)
* Added XML Docs to the files in Umbraco.Cms.Imaging.ImageSharp2

This commit fixes the missing XML documentation with the Umbraco.Cms.Imaging.ImageSharp2 project.

Now this project should have no build warnings.

* Update src/Umbraco.Cms.Imaging.ImageSharp2/UmbracoBuilderExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-24 09:34:56 +01:00
Chris HoustonandGitHub 6c40dc0d25 Added XML Docs to the files in the Umbraco.Cms.Imaging.ImageSharp (#21248)
The only build errors in this project were missing XML documentation, so I've now updated each of the files.
2025-12-24 09:33:27 +01:00
Chris HoustonandGitHub fe06cd28bf Code Quality: Fixing the build warnings in the Umbraco.Tests.Common project (#21245)
* Fixing the build warnings in the Umbraco.Tests.Common Project

The main warning was about the file name not matching the class, this was because an interface was being defined first within the class file.

This should either be moved into its own file, or to the bottom of the file to fix this warning. Rather than creating a new file, I've moved the interface to the bottom, but if you'd prefer a new file, just let me know :)

Also removed the TODO in the project file and the WarningsNotAsErrors as they have all been resolved.

* Moved the interface into it's own file.

* Removed the interfaces folder.
2025-12-23 18:11:51 +00:00
Chris HoustonandGitHub 4083ceb63a fix: Update RenderNoContentController to use non-obsolete constructor (#21246)
- Replace obsolete constructor call that used IUmbracoContextAccessor
- Use new constructor with IDocumentUrlService instead
- Add using for Umbraco.Cms.Core.Services namespace
- Remove unused Umbraco.Cms.Core.Web namespace

The obsolete constructor was scheduled for removal in Umbraco 18.
This is an internal change only - ControllersAsServicesComposer is not
shipped with Umbraco.Templates package.
2025-12-23 16:07:52 +00:00
69e7151079 Media Picker: Always include folders when searching for media (#21216)
* Always include folders when searching for media. Closes #21149

* Address copilot comments

* Resolved breaking changes.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-12-23 10:16:32 +00:00
Chris HoustonandGitHub 74c71f977c Fixes all SA1117 warnings and adding more XML documentation comments. (#21224)
This commit fixes around 1,000 build warnings related to SA1117, this warning is related to ensuring each parameter passed into a function is on a new line OR all on one line.

I have also added XML code comments to any public function within these files and fixed some that had invalid / old comments.
2025-12-23 10:34:40 +01:00
18fafaa0f3 Content: Fix property variation change breaking document save via Infinite Editing (closes #21195) (#21221)
When changing a property's variation setting (Shared/Invariant ↔ Variant) via Infinite Editing,
the document would fail to save with a 404 error.

This fix:
- Adds value migration fallback logic in UmbPropertyValuePresetVariantBuilderController
  to find values when culture/segment doesn't match exactly
- Overrides reload() in UmbContentDetailWorkspaceContextBase to process incoming data
  through _processIncomingData() for proper value transformation
- Detects property variation changes and triggers document reload to migrate values

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 16:34:47 +01:00
Niels Lyngsø f12da6e4cb Merge branch 'v16/dev' 2025-12-22 13:25:22 +01:00
Niels Lyngsø c19cc92690 optical space adjustment for content-type-designer property 2025-12-22 13:25:06 +01:00
Andy ButlandandZeegaan 2d35e32920 HybridCache: Clear published content cache on content type change (#21225)
* Clear the cacje level published content cache on content type change.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
(cherry picked from commit 396ebdd48d)
2025-12-22 15:45:06 +09:00
396ebdd48d HybridCache: Clear published content cache on content type change (#21225)
* Clear the cacje level published content cache on content type change.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-22 15:14:21 +09:00
e91c2e659d User Avatar: The "Change Photo" button is not working in all cases (#21206)
fix(user): fix avatar change and remove functionality

- Fix "Change photo" button not working on subsequent clicks by using
  { once: true } on the event listener and resetting the input value
- Fix avatar not disappearing after removal by clearing _imgSrc when
  imgUrls is set to empty array

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 09:55:25 +01:00
Andy Butland 5bb265b3a4 Merge branch 'release/17.1' 2025-12-20 09:38:59 +01:00
72e85ecaf6 TextBox: Fix max length validation message showing wrong exceeded count (#21219)
The validation message was showing the total character count instead of how
many characters exceeded the limit. For example, with max=4 and input="12345",
it showed "5 too many" instead of "1 too many".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 09:21:26 +01:00
296102c0bd Content Type Workspace: Fix navigation blocked after save (#21218)
Content Type Workspace: Sync current data after save to prevent navigation blocking

After saving a content type, only `_data.setPersisted()` was called without
`_data.setCurrent()`. An observer kept `current` in sync with the structure's
ownerContentType, but timing mismatches caused `persisted` and `current` to
differ, triggering false "unsaved changes" detection and blocking navigation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 09:10:52 +01:00
c9dcaa808b Document Permissions: Export UmbDocumentUserPermissionCondition from package (closes #21199) (#21217)
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 08:58:37 +01:00
Chris HoustonandGitHub 107fb48002 Cryptographic Functions: Fixes obsolete .NET API warnings (SYSLIB0023, SYSLIB0045, SYSLIB0021, SYSLIB0013, SYSLIB0012) by replacing deprecated cryptographic and reflection APIs with their modern equivalents. (#21213)
Fixed various obsolete .NET API calls.

These all show up as warnings when you try to build the Umbraco solution:

- SYSLIB0045 (6) - Use proper HashAlgorithm creation
- SYSLIB0023 (4) - Replace RNGCryptoServiceProvider with RandomNumberGenerator
- SYSLIB0021 (8) - Replace deprecated crypto types
- SYSLIB0013 (4) - Replace Uri.EscapeUriString
2025-12-19 21:19:41 +01:00
Chris HoustonandGitHub 7b449658d3 Fix build warning CS0252 - unintended reference comparison in tests (#21212)
Fix unintended reference comparison in tests

Explicitly casts the mock property to string in a predicate to prevent reference equality checks. Adds constraints for storage type and editor to align with expected data characteristics and improve test reliability. Keeps mock service behavior unchanged; minor formatting tweak included.
2025-12-19 21:06:55 +01:00
add5bd31c9 Management API: Fixes the warning CS8524 and tidying up the "Set Status Redirect Url Management Controller" (#21211)
* Fixes the warning CS8524 and tidying up the SetStatusRedirectUrlManagementController

I have added throwing an error in the switch statement if neither of the know enums is submitted to the API, in theory this should never happen.

The other option would be to simply return false, but I think throwing the exception is better as it will alert whoever is calling the API that their call is invalid.

* Update src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/SetStatusRedirectUrlManagementController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-19 21:04:53 +01:00
Chris HoustonandGitHub 72447b040a Resolves all CA2017 warnings and improves log message clarity (#21210)
Improves log message clarity

- Refines a warning when a property type alias is missing, clarifying that a default value is returned.
- Improves backoffice token revocation log by including contextual client id for easier troubleshooting.
- Corrects model generation error logging by passing the exception as the first argument for consistency.
2025-12-19 18:31:45 +01:00
Chris HoustonandGitHub b13544083f Docs: Fix CS1573 warnings - add missing XML param tags (#21209)
Add missing parameter documentation tags to resolve CS1573 compiler warnings:

- Add cancellationToken param tags to 24 API Management controllers

- Add payloadType param tags to 6 Webhook extension files

- Fix various missing param tags in Core and Infrastructure files
2025-12-19 18:25:08 +01:00
Nhu DinhandGitHub 70d1728843 E2E: QA Added acceptance tests for content delivery API (#21095)
* Added tests for media delivery api

* Added tests for content delivery api

* Fixed import

* Added tests for Content Delivery API

* Updated skip tag and issue link for the failing tests

* Bumped version

* Refactor code for content delivery api tests

* Moved repeat steps to beforeEach and added more waits

* Bumped version

* Added more waits

* Updated variable names

* Grouped tests

* Renamed

* Fixed names
2025-12-19 10:16:19 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Jacob Overgaard
c08e39064f Storybook: Bumps storybook from 9.0.14 to 10.1.10 (#21208)
* Bump storybook

Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client directory: [storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/core).


Updates `storybook` from 9.0.14 to 9.1.17
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v9.1.17/code/core)

---
updated-dependencies:
- dependency-name: storybook
  dependency-version: 9.1.17
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps-dev): bumps storybook from v9 to v10

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2025-12-19 10:13:31 +00:00
Nhu DinhandGitHub dfb7507ae2 E2E: QA Added acceptance tests for rendering content with invariant blocks (#21180)
* Added tests for rendering content with block list

* Updated tests for rendering content with block lists

* Updated message when has no block lists

* Added tests for rendering content with block grid

* Updated code

* Bumped version

* Changed npm command to make tests run in the pipeline

* Fixed comment

* Reverted command
2025-12-19 09:25:17 +00:00
d749af8974 Upgrade MSW from 1.3.5 to 2.12.4 (#21096)
* upgrade msw, migrate all interceptors, and update backoffice integration

* Fix msw test runner integration

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2025-12-19 10:19:10 +01:00
Nhu DinhandGitHub 14fe6f4888 E2E: QA Fixed failing tests for the current user profile (#21214)
* Added more waits

* Make tests run in the pipeline

* Reverted npm command
2025-12-19 09:18:45 +00:00
Chris HoustonandGitHub 0d4f24300a fix(code-quality): resolve CS0628 warnings - change protected to private in sealed classes. (#21193)
* fix(code-quality): resolve CS0628 warnings - change protected to private in sealed classes

Changed protected members to private in sealed classes across 26 files. Protected members in sealed classes serve no purpose since sealed classes cannot be inherited. This eliminates 57 CS0628 compiler warnings.

* fix: use public for NUnit SetUp methods per Copilot review

NUnit requires SetUp methods to be at least protected. Using public
avoids CS0628 while allowing NUnit to discover and execute the methods.

* Clean up

- Renames internal fields to clearer names and aligns with conventions
- Changes internal cache holder to use auto-properties for state ( fixes another build warning )
- Removes an unused exception type from the loader and cleans up unused usings
- Adds "Umbraco" to the list of known spellings in .vsCode settings file, amazed this wasn't already there :)

* Improvements to fix CodeScene Code Health Review issues.

- Introduces debug-only logging helpers and routes all log messages through them for consistency
- Centralizes retrieval of discoverable types and scanning logic to simplify paths
- Aligns logging of cached vs non-cached and slow paths with new helpers
- Documents data-holding structure used to store type lists for clarity

* Refactoring to make CodeScene happy, removing code duplication :)
2025-12-18 19:28:13 +01:00
Engiber LozadaandGitHub ebb6590bad Data Types: Add condition to hide delete action in non deletable data types. (#21184)
* Created a condition that check non deletable data types.

* Export condition.

* Updated export path.
2025-12-18 09:58:29 +00:00
Niels LyngsøandGitHub 7b85109606 News Dashboard: Update styling to fit with new style (#21185)
styling of the dashboard
2025-12-18 09:51:11 +01:00
Chris HoustonandGitHub 0e60602746 Tests: Fix CS4014 warnings - add missing await operators (#21194)
Fix unawaited async calls in tests

- Converts setup to async and awaits data creation
- Awaits operation status update to fix potential unawaited calls
- Updates nested validation tests to use await for helper results
- Removes stray BOM character in a test file
- Improves overall async flow, addressing CS4014
Relates to CS4014
2025-12-18 07:03:23 +01:00
Mads RasmussenandGitHub e08a60e74d Performance: Embed Store API in Manifests to lower number of network request (#21191)
Refactor manifests to use direct store imports to minimize the number of lazy loaded items on startup
2025-12-17 23:13:39 +01:00
Niels LyngsøandGitHub 4c7abc41b2 Performance: Bundle Js Libs (#21187)
bundle libs
2025-12-17 21:41:58 +00:00
Niels LyngsøandGitHub 45ae5aaac0 Performance: Embeds the API of selected extra Conditions (#21188)
embeds the API of selected Conditions
2025-12-17 21:43:08 +01:00
Niels LyngsøandGitHub 30d9288f12 Culture and Hostnames: Load all languages (#21169)
make sure we take all languages
2025-12-17 16:01:20 +01:00
Kenn JacobsenandAndy Butland 4aa506100e Indexing: Gracefully handle element property variance changes at index time (#21183)
Gracefully handle element property variance changes at index time
2025-12-17 15:53:14 +01:00
700a19f4b9 Block level variance: fix values being polluted when changing variance before publish (#21121)
* TDD solution to Block level variance publishing changing to no variance retaining block level variance values and vica versa

* Add similar tests for the other block editors

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Amend the test scenarios

* Simplify the merge clean-up to remove all misaligned values.

* Fix failing test (remove false assumptions)

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2025-12-17 15:52:56 +01:00
Niels Lyngsø e27b661b3f update version in package lock 2025-12-17 15:51:12 +01:00
Kenn JacobsenandGitHub 75e4b2b18d Indexing: Gracefully handle element property variance changes at index time (#21183)
Gracefully handle element property variance changes at index time
2025-12-17 15:44:09 +01:00
8642b9e615 Content Types: Fix property variation change when content exists only in non-default language (#21182)
* Content Types: Fix property variation change when content exists only in non-default language (closes #11771)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add tests for AllowEditInvariantFromNonDefault enabled scenario

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 15:21:17 +01:00
7b9bef9d2a Content Types: Fix property variation change when content exists only in non-default language (#21182)
* Content Types: Fix property variation change when content exists only in non-default language (closes #11771)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add tests for AllowEditInvariantFromNonDefault enabled scenario

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 15:19:38 +01:00
638e181334 Content Types: Fix property variation change when content exists only in non-default language (#21182)
* Content Types: Fix property variation change when content exists only in non-default language (closes #11771)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add tests for AllowEditInvariantFromNonDefault enabled scenario

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 15:18:14 +01:00
254400bb58 Block level variance: fix values being polluted when changing variance before publish (#21121)
* TDD solution to Block level variance publishing changing to no variance retaining block level variance values and vica versa

* Add similar tests for the other block editors

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Amend the test scenarios

* Simplify the merge clean-up to remove all misaligned values.

* Fix failing test (remove false assumptions)

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2025-12-17 13:51:19 +01:00
3bcdcc56c8 Cache: Add null checks for entities that may no longer exist during cache refresh (#21181)
* Add null checks in case content no longer exists

* Add logging statement

* Add integration tests for null handling in cache refresh services

Tests verify that DocumentUrlService and PublishStatusService
do not throw exceptions when called with non-existent content keys,
which can happen when processing stale cache instructions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add integration tests for stale cache instruction handling

Tests simulate the scenario where a cache instruction is processed
for content that has been deleted (stale instruction). This can happen when:
1. Content is saved (cache instruction queued)
2. Content is deleted before instruction is processed
3. Server restarts and processes the stale instruction

Tests cover:
- ContentCacheRefresher with RefreshBranch for deleted content
- ContentCacheRefresher with RefreshNode for deleted content
- MediaCacheRefresher with RefreshBranch for deleted media
- Processing instructions for content that never existed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 11:44:07 +01:00
Nhu DinhandGitHub dd6ae8bd25 E2E: QA Added acceptance tests for removing a not-found content picker (#21177)
* Added tests for removing a not-found content picker

* Added comment

* Bumped version

* Change npm command to make tests run in the pipeline

* Reverted npm command
2025-12-17 09:38:39 +00:00
Andreas ZerbstandGitHub aa32035830 E2E QA: Updated integration test that was missing directory setup (#21167)
* Added base class

* Added implementation of base class

* Added missing parameter

* Added try-catch around delete operations in Purge() to ignore locked files during cleanup.
2025-12-17 09:57:17 +01:00
911d2fe67b Content: Fix name() and getName() to use active variant (closes #20759) (#21171)
* Content: Fix name() and getName() to use active variant when no variantId provided

When calling `name()` or `getName()` without a variantId argument, the methods
now correctly return the name of the first active variant from the split view
instead of always returning the first variant in the data array.

The `name()` method now returns a reactive observable that updates when the
active variant changes, using `mergeObservables` to combine the split view's
active variant observable with the variants data.

The `getName()` method now uses `splitView.getActiveVariants()[0]` to get the
current active variant synchronously, with a fallback to the first variant if
no active variant is set.

This fixes an issue where block previews could not reactively observe the
document name because the callback parameter was always empty.

Closes #20759

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: use UmbVariantId.compare() for consistent variant matching

Address PR review feedback by using UmbVariantId.Create() and compare()
instead of direct property comparison. This ensures consistent behavior
with the existing variant comparison pattern used throughout the codebase.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: formatting

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 08:48:42 +01:00
Sven GeusensandAndy Butland 235fa3b743 Added a migration to remove the property regex validation length limit (#21175) 2025-12-17 06:49:02 +01:00
Sven GeusensandGitHub 81685bf0e2 Added a migration to remove the property regex validation length limit (#21175) 2025-12-17 06:48:36 +01:00
Andy Butland 9fb018276a Bumped version to 17.2.0-rc. 2025-12-17 06:41:09 +01:00
Andy ButlandandGitHub a9c6f97f7b Models builder: Re-provide support for casting a published member to the models builder type (closes #21135) (#21150)
* Re-provide support for casting a published member to the models builder type.

* Used new constructor for MemberManager in unit tests.

* Fix failing unit tests.
2025-12-17 06:37:15 +01:00
Laura Neto 179f2e709d Merge branch 'main' into v18/dev 2025-12-16 15:44:08 +01:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>nielslyngsoe
044cd1da57 Add loader to Culture and Hostnames modal while data loads (#21084)
* Initial plan

* Add loader to culture-and-hostnames modal with undefined state tracking

Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: nielslyngsoe <6791648+nielslyngsoe@users.noreply.github.com>
2025-12-16 14:06:50 +00:00
Niels LyngsøandGitHub 871d590f9a refactor multi url picker validation (#21143)
* refactor multi url picker validation

* fix line break
2025-12-16 13:36:33 +00:00
b207fa31cd Relations: Fix descendants query to exclude parent item (#21162)
* Relations: Fix descendants query to exclude parent item

The GetPagedDescendantsInReferences query was using a path LIKE without
the comma delimiter, causing it to match both the parent item and its
descendants. This resulted in the trash confirmation dialog showing
the item being deleted in the "descending items with dependencies"
list.

Changed the WhereLike call to use ",%" suffix instead of just "%",
so the query only matches actual descendants (items whose path
starts with the parent's path followed by a comma).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add integration test to verify behaviour.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-12-16 13:44:21 +01:00
Andreas ZerbstandGitHub 2a604c8719 E2E: QA Replaced unreliable Thread.Sleep(500) with a counter/gate pattern that ensures both transactions are initialized before releasing them to compete for locks (#21165)
Fix flaky test
2025-12-16 12:02:07 +00:00
Laura NetoandGitHub dab88d7019 Document Saving: Fix SQL Server deadlock during concurrent updates (#21156)
Fix SQL Server deadlock during concurrent document updates

Add ReadLock on ContentTree in RefreshMemoryCacheAsync to prevent
deadlocks between cache refresh SELECT queries and concurrent document
UPDATE operations. The deadlock occurred because the operations accessed
umbracoNode and umbracoDocument tables in different orders.
2025-12-16 11:42:49 +01:00
5bd35288f5 Tree: Fix race condition when loading tree with hideTreeRoot enabled (#21160)
The #debouncedLoadTree method was not awaiting repository initialization
before calling loadChildren() when hideTreeRoot was true. This caused a
"repository is missing" error in tree pickers like the Static File picker
used for block thumbnails.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 10:35:09 +00:00
c2730e7308 UI: Prevent headline overflow in umb-body-layout (#21140)
* fix: add title attribute and prevent headline overflow in body layout

* Added min-width property.

---------

Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2025-12-16 09:24:56 +00:00
Andreas ZerbstandGitHub 6419585443 E2E: QA Added acceptance tests for issue #20815 (#21151)
* Added tests for making sure that nested variants properties are updated

* Updated failing test

* Bumped version

* Cleaned
2025-12-16 08:38:39 +00:00
Nhu DinhandGitHub dc61f93afe E2E: Added acceptance tests for regression issues (#21098)
* Added tests for regression issue #20962

* Added tests for regression issue #20520

* Added tests for rendering content with RTE

* Added @release tags

* Bumped version

* Make new added tests run in the pipeline

* Updated dataTypeName

* Fixed comments

* Reverted npm command
2025-12-16 07:43:48 +00:00
MoleandGitHub 7982641262 Distributed Background Jobs: Catch exceptions in job loop to improve application resilience (#21099)
* Set exit code when exception is thrown

* Catch any error instead so we don't stop the application

* Handle exception when ensuring jobs
2025-12-16 06:56:04 +01:00
85806fd7b5 Performance: Re-introduce lazy locks (#21102)
* fix: add write lock at outer scope to prevent deadlocks in content publishing

Acquire a write lock on ContentTree at the start of PublishAsync to prevent
deadlocks. Previously, inner scopes would acquire read locks first (via
repository operations), then attempt to upgrade to write locks, causing
deadlocks when multiple transactions tried this simultaneously.

By acquiring the write lock at the outer scope, we ensure consistent lock
ordering and prevent the deadlock scenario.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Re-enable lazy locks

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 06:53:34 +01:00
Laura NetoandGitHub 57cec15928 Content Types: Introduce schema service to support future schema generation (#21031)
* Introduce new content type schema service and models

To be used in the future for content type schema generation.

* Do not fail when content type is not in cache, simply ignore

* Added unit and integration tests

* Fix failing unit tests

* Addressing comments from code review
2025-12-15 20:52:46 +01:00
Andy Butland 59aaa00bab Merge branch 'v16/dev'
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/assets/lang/en.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-picker-modal/icon-picker-modal.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/performance-profiling/dashboard-performance-profiling.element.ts
2025-12-15 19:57:30 +01:00
a429170842 Extend RTE output in Delivery API for better support for multi-site URL resolution (#20846)
* add content key and type to link info on RTE delivery API data. Fix tests to accomodate changes

* convert field type content-id -> destination-id. convert field type content-type -> link-type and use LinkType enum instead.

* revert unintended find and replace changes

* apply patch by kjac

* fix unit tests for RTE parsers

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2025-12-15 15:23:11 +01:00
9c0a0a1086 V16/drag event media (#20893)
* updates the drag event to convert types to lowercase

* clearing up

* clearing up

* Fixed style problem in safari and an unused parameter.

* Fixed lint error.

---------

Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
2025-12-15 14:16:57 +00:00
+2 0845d267e6 Block Editors: variantId inheritance fix (#21101)
* block context example

* fix clone method

* implement contextual variant id

* use contextual variant id

* ensure currentExposeOf uses elementType configuration

* make hasExposeOf use ElementType configuration for variatId

* Update src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* rename to displayVariant

* use variantid in this case

* update readme

* return false

* remove unused imports

* return undefined

* append UmbWorkspaceViewElement interface

* remove test

* fallback to false

* fallback to false

* refactor what is not exposed.

* Fix #20944: Updating UI Slider number properties to accept decimal values (#20945)

* updating UI slider properties min, max, initial1, initial2 and step to accept decimal values

* Changes based on Copilot suggestions

* Used a smaller step value configuration.

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>

* Manifests: Fix misnaming and mis-registering of the document validation manifest (closes #21128) (#21139)

Fix misnaming and mis-registering of the document validation manifest.

* Performance: Optimize memory footprint of document URL cache (closes #21055) (#21066)

* Optimize memory footprint of document URL cache.

* Update tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/DocumentUrlServiceTests.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Used properties, added some further comments.

* Fixed failing integration tests.

* Ensure no edge case exists where the culture code to language Id map isn't up to date with the newly created languages.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Block List: Sort mode (#21060)

* Block List: added sort-mode

* Fix missing closing bracket

* register sort mode toolbar element on start up

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.ts

* Update nightly build to include 16 as 17 is now main (#21144)

* Global search items missing Umbraco url segment (#20266)

* Add /umbraco url Segament for searched mapped results to aviod 404 og navigation away from backoffice

* Applied changes from code review.

---------

Co-authored-by: Lucas Bach Bisgaard <lucas.bisgaard@kraftvaerk.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>

* import

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jason Andrae <jasona@emergentsoftware.net>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Lee Kelleher <leekelleher@users.noreply.github.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Sven Geusens <sge@umbraco.dk>
Co-authored-by: Lucas Bach Bisgaard <rammi@rammi.dk>
Co-authored-by: Lucas Bach Bisgaard <lucas.bisgaard@kraftvaerk.com>
2025-12-15 13:31:51 +00:00
6c743e8270 Tiptap RTE: Uses UmbracoCssPath global setting when loading CSS files (closes #20877) (#21106)
* get full path of file

* get configuration umbracosspath from BE and use it when get css file

* fix lint error

* update for test fail

* add obsolete constructor

* Update src/Umbraco.Cms.Api.Management/Controllers/Server/ConfigurationServerController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Update src/Umbraco.Cms.Api.Management/Controllers/Server/ConfigurationServerController.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Added `umbracoCssPath` to mock Server handler

* Added `umbracoCssPath` to Server Connection controller

* Removed the Tiptap Config Repository/Store code

we can simplify this by reusing the Server Context.

* Used `UMB_SERVER_CONTEXT` to get the `umbracoCssPath`

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-12-15 14:14:40 +01:00
d47464e2a7 Global search items missing Umbraco url segment (#20266)
* Add /umbraco url Segament for searched mapped results to aviod 404 og navigation away from backoffice

* Applied changes from code review.

---------

Co-authored-by: Lucas Bach Bisgaard <lucas.bisgaard@kraftvaerk.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-12-15 11:51:29 +00:00
Sven GeusensandGitHub e8adb30411 Update nightly build to include 16 as 17 is now main (#21144) 2025-12-15 11:33:33 +01:00
fb1e52a172 Block List: Sort mode (#21060)
* Block List: added sort-mode

* Fix missing closing bracket

* register sort mode toolbar element on start up

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2025-12-15 11:22:11 +01:00
452c56b882 Performance: Optimize memory footprint of document URL cache (closes #21055) (#21066)
* Optimize memory footprint of document URL cache.

* Update tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/DocumentUrlServiceTests.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Used properties, added some further comments.

* Fixed failing integration tests.

* Ensure no edge case exists where the culture code to language Id map isn't up to date with the newly created languages.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-15 11:19:44 +01:00
Andy ButlandandGitHub aeca0d0f29 Manifests: Fix misnaming and mis-registering of the document validation manifest (closes #21128) (#21139)
Fix misnaming and mis-registering of the document validation manifest.
2025-12-15 09:10:29 +00:00
fa23e1874c Fix #20944: Updating UI Slider number properties to accept decimal values (#20945)
* updating UI slider properties min, max, initial1, initial2 and step to accept decimal values

* Changes based on Copilot suggestions

* Used a smaller step value configuration.

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
Co-authored-by: engjlr <enl@umbraco.dk>
2025-12-15 09:00:12 +00:00
Sven GeusensandGitHub 906f8e4664 QA Added unit tests for HideBackOfficeTokensHandler (#21067)
* Added unittests for the HideBackOfficeTokensHandler
2025-12-15 09:43:39 +01:00
63fd7ddc52 Repositories: Optimize repository caches to populate for both int and GUID keys (#21124)
* Populate repository cache by GUID when retrieving documents by integer ID, to avoid database hit on subsequent retrieval by key.

* Apply same for media repository.

* Use existing helper to centralise generation of repository cache keys.

* Minor clean-up.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Applied suggestions from code review.

* Apply suggestions from code review

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* Applied suggestions from code review.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2025-12-15 07:17:57 +01:00
5569607a81 Workspace: Fix browser title not being set correctly (#21126)
* Block Workspace: Only update view title when opened in modal context

Prevents unintended document title updates when block workspace is used
outside of modal context. Also adds early return in view controller when
no local title is available to avoid setting an empty title prefix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* View Controller: Reactivate parent view when child is removed

When a non-inheriting child view (like a modal) is removed, the parent
view may have been deactivated. This change ensures the parent view is
reactivated to restore the browser title when the modal closes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/view/context/view.controller.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-12 15:44:46 +00:00
9a0d2d1f97 Update src/Umbraco.Web.UI.Client/src/packages/tiptap/CLAUDE.md
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-12 16:30:33 +01:00
leekelleherandJacob Overgaard 99a1a612ce Corrected directory structure layout 2025-12-12 16:30:33 +01:00
leekelleherandJacob Overgaard 0119d8d4da docs: Add CLAUDE.md documentation for Tiptap RTE 2025-12-12 16:30:33 +01:00
Nhu DinhandGitHub 0e90b072c8 E2E: QA Fixing some failing tests related to culture and hostname, log viewer and user (#21132)
* Bumped version

* Updated tests to match new changes

* Bumped version

* Bumped version
2025-12-12 20:02:46 +07:00
08a95b64fe Docs: Add PR naming convention to CLAUDE.md (#21114)
* Docs: Add PR naming convention to CLAUDE.md

Integrate the PR naming guidelines from PullRequestNaming.md into the
Pull Request Process section of CLAUDE.md for better discoverability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove area

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 12:06:46 +00:00
Nicklas KramerandGitHub 08aa10b4f7 Media: Fixing media folder not getting deleted when deleting media files. (#21059)
* Introducing lock and logic to find directory to be deleted

* Obsoleting old ctor

* Expanding obsolete comment

* Adding new parameter to tests

* Adding database to failing integration tests.

* Adding more tests

* Fixing flawed logic

* Cleanup on FileSystemsTests.cs
2025-12-12 17:32:27 +09:00
Lee KelleherandGitHub 8e3764e4fb UFM: Resolves "missing filter" console warning (#21118)
UFM Filter base, check that the component is connected to the DOM

otherwise the context no longer exists and the `render` still runs,
giving a bunch of "missing filter" warnings.
2025-12-11 13:28:32 +01:00
Laura Neto 90c09b1bf1 Merge branch 'main' into v18/dev
# Conflicts:
#	tests/Umbraco.Tests.Integration/CompatibilitySuppressions.xml
2025-12-11 10:17:18 +01:00
Andy Butland 7492009dc6 Merge branch 'release/17.0'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-12-11 07:07:24 +01:00
Andy Butland 1a4256f997 Add option to hide colors from icon picker (#20650)
* Add option to hide colors from icon picker

* Hide colors

* Hide colors from config
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/core/icon-registry/icon-picker-modal/icon-picker-modal.element.ts
2025-12-11 06:57:29 +01:00
Bjarne FyrstenborgandGitHub 23e8ee51d3 Add option to hide colors from icon picker (#20650)
* Add option to hide colors from icon picker

* Hide colors

* Hide colors from config
2025-12-11 06:40:28 +01:00
30a57dd5f5 Content Publishing: Fix deadlocks by acquiring WriteLock at outer scope (#21105)
fix: add write lock at outer scope to prevent deadlocks in content publishing

Acquire a write lock on ContentTree at the start of PublishAsync to prevent
deadlocks. Previously, inner scopes would acquire read locks first (via
repository operations), then attempt to upgrade to write locks, causing
deadlocks when multiple transactions tried this simultaneously.

By acquiring the write lock at the outer scope, we ensure consistent lock
ordering and prevent the deadlock scenario.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 20:59:38 +01:00
3fa053ae4c Delivery API: Adding allow list for content types (#21111)
* Adding allow content type alias settings and validator

* Creating private helper method for tests

* Revisiting logic for disallow types

* Adding tests for validator

* Obsolete unnecessary methods and overloads.

* Fix warning and update naming in tests.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-12-10 16:43:39 +00:00
7b13e23025 Templating: Creating a doctype with template now yields a strongly typed template (closes #20443) (#20688)
* Adjust the document type creation flow so that a template can be created for a content type

Add id, name and alias to the request payload to allow creating multiple templates for the same document type

Small adjustments

Remove unused import and unnecessary async

Switched content type template creation to content type controller

Missing constant export

# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts

* Add default implementation for CreateForContentTypeAsync

* Small adjustments from code review

* Introduce InvalidTemplateAlias content type operation status

* Add tests for CreateTemplateAsync and fix alias validation

- Add integration tests for ContentTypeService.CreateTemplateAsync:
  - Success case with template association
  - NotFound status for non-existent content type
  - InvalidTemplateAlias for empty and too-long aliases
  - Default template assignment verification

- Fix bug in TemplateService.CreateAsync where alias validation
  occurred after GetViewContent call, causing ArgumentNullException
  for invalid aliases instead of returning InvalidAlias status

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 17:36:42 +01:00
Laura NetoandGitHub 8c187a699f Long Running Operations: Ensure eager write lock (#21113)
Use EagerWriteLock for long running operations

Switch from WriteLock to EagerWriteLock when acquiring the lock for
long running operations to ensure proper lock acquisition timing.
2025-12-10 15:24:45 +00:00
e08d80f084 Add Context7 claim file (#21110)
Adds context7.json to claim this repository for Context7 documentation service.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Phil Whittaker <pjw@umbraco.dk>
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-10 15:32:00 +01:00
f5e6d85769 Distributed Background Jobs: Add initialization logging to DistributedJobService (#21112)
* Distributed Background Jobs: Add initialization logging to DistributedJobService

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Use registered instead of intitialized

* Update src/Umbraco.Infrastructure/Services/Implement/DistributedJobService.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Be consistent in log messages

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-10 15:03:34 +01:00
497c31ef2c Sync: Fix SyncBootStateAccessor to use ILastSyncedManager to prevent unnecessary cold boots (#21109)
* Sync: Fix SyncBootStateAccessor to use ILastSyncedManager

Update SyncBootStateAccessor to use the new ILastSyncedManager interface
instead of the deprecated LastSyncedFileManager, which was causing cold
boots to be triggered every time.

- Replace LastSyncedFileManager field with ILastSyncedManager
- Add new primary constructor accepting ILastSyncedManager
- Add obsolete constructors for backwards compatibility using StaticServiceProvider
- Update GetSyncBootState to use GetLastSyncedExternalAsync

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Sync: Add integration tests for SyncBootStateAccessor

Add integration tests to verify SyncBootStateAccessor correctly
determines cold boot vs warm boot state based on ILastSyncedManager.

- Test cold boot when no last synced ID exists
- Test warm boot when last synced external ID matches a cache instruction

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 14:38:09 +01:00
1a4ca0ba4d Sync: Fix SyncBootStateAccessor to use ILastSyncedManager to prevent unnecessary cold boots (#21109)
* Sync: Fix SyncBootStateAccessor to use ILastSyncedManager

Update SyncBootStateAccessor to use the new ILastSyncedManager interface
instead of the deprecated LastSyncedFileManager, which was causing cold
boots to be triggered every time.

- Replace LastSyncedFileManager field with ILastSyncedManager
- Add new primary constructor accepting ILastSyncedManager
- Add obsolete constructors for backwards compatibility using StaticServiceProvider
- Update GetSyncBootState to use GetLastSyncedExternalAsync

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Sync: Add integration tests for SyncBootStateAccessor

Add integration tests to verify SyncBootStateAccessor correctly
determines cold boot vs warm boot state based on ILastSyncedManager.

- Test cold boot when no last synced ID exists
- Test warm boot when last synced external ID matches a cache instruction

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 13:02:10 +00:00
8626ae4f2e Distributed Background Jobs: Improve distributed background job locking behavior and performance (#21100)
* Don't take jobs that's already running and handle stale jobs

* Add tests

* Add bulk insert and delete methods to repository

* Optimize EnsureJobsAsync to use batch inserts

* Add EnsureJobs tests

* Remember to keep old constructor

* Minor cleanup

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2025-12-10 11:23:38 +01:00
Lotte PitcherandAndy Butland 78dfcf97b7 Dotnet new templates: Fix placeholders and port in umbraco-extension template (#20956)
* reset placeholders and port number in umbraco-extension template

* add readme instructions on how to test templates locally
2025-12-10 07:06:29 +01:00
Niels LyngsøandGitHub f8d6a97196 Blocks: localize group headline (#21090)
localize block group headline
2025-12-09 09:17:20 +01:00
c910f544ee Improve deletion logic in UmbracoContentIndex (#21091)
* Improve deletion logic in UmbracoContentIndex

When re-indexing a node it will first delete it, however in many cases the query to delete doesn't return anything, however a delete command is still executed with an empty integer collection. We can avoid allocating and iterating lists and avoid the deletion call all together if the collection is empty.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Clean-up and warning resolution whilst we are modifying class.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-09 08:01:48 +00:00
Niels Lyngsø 0d599f6639 formatting 2025-12-08 15:23:24 +01:00
cbc832d6f3 Collection: Introduce Card and Ref Collection View kinds (#21037)
* Add entity collection item card extension type + default elements

* implement user collection item card

* fix selection events

* map to prop

* add prop/attr for href

* add support for which detail properties to show

* update type import

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/item/entity-collection-item-card/entity-collection-item-card.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* import card in correct file

* Fix event listener binding for selection events

* implement disabled property for collection item cards

* init commit of collection item ref extension

* fix imports

* add element interface

* Implement UmbEntityCollectionItemElement interface in item cards

Added the UmbEntityCollectionItemElement interface to document and user collection item card elements for improved type safety and consistency. Updated type exports to include the new interface.

* Update collection item ref to use uui-ref-node

Replaces the placeholder div with a uui-ref-node component, passing relevant item properties and event handlers. Adds dynamic icon rendering using umb-icon.

* Refactor entity collection item elements to use shared base

Introduces a new abstract base class for entity collection item elements, consolidating shared logic for card and ref variants. Updates card and ref element implementations to extend the new base, and refactors extension manifest interfaces for consistency. This improves maintainability and reduces code duplication.

* use class instead of magic string

* introduce ref and card collection view kinds

* Utilise card kind for user collection view

* Add item-specific href support to collection views

Introduces a requestItemHref method to collection contexts for retrieving item-specific hrefs. Updates card, ref, and user table collection views to use these hrefs, enabling dynamic linking for collection items. Refactors user table name column layout to accept href via value prop instead of constructing it internally.

* Update ManifestCollectionView import path

Changed the import of ManifestCollectionView from '../extensions/types.js' to '../view/types.js' to reflect its new location.

* use box

* render entity actions

* use edit path builder for user links

* rename method

* Revert "rename method"

This reverts commit 4df577688e.

* Update collection-default.context.ts

* make type lint ignore unused args with an underscore

* temp remove unused

* only make collection vie selectable if there are any registered bulk actions

* don't render name link if there is no href

* fix imports

* use selectable state

* Update language-table-collection-view.element.ts

* Update card-collection-view.element.ts

* clean up

* Refactor collection views to use shared base class

* refactor(collection): parallelize href fetching and make method private

* docs(examples): update collection example to use card and ref kinds

* docs(examples): add icon property to collection example data model

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/view/types.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update collection-bulk-action.manager.test.ts

* Removed duplicate and redundant '@typescript-eslint/no-unused-vars' rule definitions, consolidating the configuration to use only 'argsIgnorePattern'.

* Handle missing user href in name column layout

Replaces the user name link with a span when the href property is not provided, preventing broken links in the user table name column layout.

* Update user-table-name-column-layout.element.ts

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-08 11:18:28 +00:00
Jacob Overgaard 4bf83a70c1 build: adds keywords to package.json 2025-12-08 10:35:55 +01:00
d7d52dd488 fix(rte): Deduplicate Tiptap extensions to prevent duplicate name warnings
When multiple Umbraco extensions (e.g., BulletList and OrderedList) include
the same Tiptap extension (ListItem), duplicates were added to the extensions
array, causing Tiptap to log warnings. This change uses a Map to deduplicate
extensions by their name property before passing them to the Editor.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 09:53:37 +01:00
475010148b Added 'mandatory' tag as a visual indicator for webhook events being … (#21075)
* Added 'mandatory' tag as a visual indicator for webhook events being mandatory.

* Map the webhook validation for no events specified to a specific API response problem details message.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-12-05 15:44:33 +00:00
830250b682 Docs: Update outdated branch references from contrib to main (#21072)
The contributing documentation still referenced the old `contrib` branch,
which was causing AI tools to incorrectly use it as the base branch for
comparisons. Updated all references to use `main` instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-05 14:24:40 +00:00
fd4ed2cfc1 Back-office auth: Calculate token cookie names at request time (Closes #21050) (#21056)
* Back-office auth: Calculate token cookie names at request time

The __Host- cookie prefix enforces secure cookies at browser level,
which caused cookies to be rejected when running over HTTP in local
development environments even when UseHttps was set to false.

Cookie names are now calculated per-request based on both the UseHttps
setting and whether the current request is over HTTPS, matching the
logic used for the Secure cookie option.

* Update src/Umbraco.Cms.Api.Common/DependencyInjection/HideBackOfficeTokensHandler.cs

Co-authored-by: Sven Geusens <sge@umbraco.dk>

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2025-12-05 11:04:31 +01:00
Andy Butland 80ae0380a2 oEmbed Providers: Updated the X oEmbed provider to use the x.com domain (closes #21052) (#21053)
* Updated the X oEmbed provider to use the x.com domain.

* Fixed issues raised in code review.
2025-12-05 10:55:09 +01:00
Nicklas KramerandGitHub 15b2cb7bd1 News Dashboard: Adding functionality to overwrite the cache duration (#21064)
* Adding functionality to overwrite the cacheduration for NewsDashboard

* Making the extension its own class, as to avoid having to inherit the entire service.

* Changing options to duration and adding interface
2025-12-05 10:43:43 +01:00
Andy ButlandandGitHub 5683ae9e4b oEmbed Providers: Updated the X oEmbed provider to use the x.com domain (closes #21052) (#21053)
* Updated the X oEmbed provider to use the x.com domain.

* Fixed issues raised in code review.
2025-12-05 10:38:58 +01:00
b6580ed40c E2E: QA updated current accceptance test project README to match current project (#21063)
* Updated readme

* Update tests/Umbraco.Tests.AcceptanceTest/README.md

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/README.md

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

---------

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2025-12-05 07:43:34 +00:00
Andy Butland 9340842ee2 Bump version to 17.0.2. 2025-12-05 06:47:46 +01:00
Andy Butland fd01282798 Merge branch 'release/16.4.1' into v16/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-12-05 06:44:51 +01:00
f7ba2eaa62 Property Editors: Hide "add button" when maximum configuration is 1 (fixes #20407) (#20738)
Hide add button when max 1

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2025-12-04 16:34:10 +01:00
9485a95c0e Image cropper modal import missing component (#20651)
* Import missing component

* Handle nullable type

* Vertically center image

* Add minimum width for SVG without dimensions

* 100% height until max height

* 100% height minus top/bottom padding

* Revert "100% height minus top/bottom padding"

This reverts commit 67ada4c70f4b75dfcfa2b54ce139ec7465a17ce1.

* Revert "Handle nullable type"

This reverts commit 3130e11a4be83a18b5a7d8c1c24ee23c94d8765d.

* Removed flexbox style

* Fixed circular dependency

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-12-04 16:32:10 +01:00
Lotte PitcherandGitHub 61a69852e3 Dotnet new templates: Fix placeholders and port in umbraco-extension template (#20956)
* reset placeholders and port number in umbraco-extension template

* add readme instructions on how to test templates locally
2025-12-04 15:34:57 +01:00
e6c7ef8904 Segments: Only validate segment values for cultures they are defined for (closes #21029) (#21033)
* Only validate segment values for cultures they are defined for.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Integration test suppressions.

* Remove previous implementation using ISegmentService and rely on values provided in the model to determine segments with cultures.

* Omit null culture and remove passing but unrealistic tests.

* Fixed nullability error.

* Apply suggestions from code review

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>

* Relocated function following code review.

* Reset unchanged files.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2025-12-04 12:54:44 +01:00
effccef81d Collections: Add selection mode toggle in UmbTableElement update lifecycle (#20486)
* Add selection mode toggle in UmbTableElement update lifecycle

* Update src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Markup attribute consistency

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-12-04 11:25:19 +00:00
Laura Neto e7719c2458 Cleanup compatibility suppressions 2025-12-04 11:15:19 +01:00
Laura Neto fbce5882c6 Set up new v18 branch 2025-12-04 11:03:26 +01:00
88f04cd722 Document Tree: Fix undefined name for variants without fallback. (#21046)
* fix(backoffice): Tree menu item shows undefined for variant names without fallback

When a document variant has no name set and there's no fallback language
configured, the tree now falls back to the first variant with any name
instead of displaying "undefined".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(backoffice): Show (Untitled) when no variant has a name

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 10:01:57 +00:00
Nicklas KramerandGitHub 26efa520bc Packaging: Fixing bad serialization for data types in packages (#21043)
* Changing data type serialization to datatype

* Moving and correcting comment
2025-12-04 10:52:23 +01:00
f1ab605bb9 Debug mode: Marks UMB-DEBUG cookie as HttpOnly and Secure (#21032)
* fix: sets profiling cookie to httpOnly and strict in order to run non-secure

* fix: adds extra message to explain when you can set a cookie

* fix: simplify cookie explanation comment in WebProfilerRepository

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: checks that the profiler is actually enabled and/or disabled and warns the user if that is not the case

* Update src/Umbraco.Web.UI.Client/src/assets/lang/en.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 10:24:12 +01:00
d8c03c426e Property Editors: Fix localization of user-provided labels (closes #20974) (#21045)
* fix: uses localization string() to localize user-provided labels

* fix: localizes placeholder as well

* Refinements to the Toggle input

The localizations can happen in the `config` setter,
then they don't need to re-get the localization each re-render.

Added a `when` directive to show/hide the label `<span>` tag.

Removed `_currentLabel` as unused.

* Refinements to the Textbox input

The localizations can happen in the `config` setter,
then they don't need to re-get the localization each re-render.

Refactored the `uui-input` attributes/properties.

* Refinements to the Number input

The localizations can happen in the `config` setter,
then they don't need to re-get the localization each re-render.

Refactored the `uui-input` attributes/properties.

* Update src/Umbraco.Web.UI.Client/src/packages/core/components/input-toggle/input-toggle.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/property-editors/text-box/property-editor-ui-text-box.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/property-editors/number/property-editor-ui-number.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Updates based on Copilot feedback

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
Co-authored-by: Lee Kelleher <leekelleher@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 09:20:33 +00:00
455e7027a0 Block Grid: Sort mode (#20869)
* Added `icon-sort`

from Lucide's "arrow-down-up" icon.

* Added "Sort" package

with property action and context.

* Adds the "sort" property action and context to the Block Grid property

* [WIP] Observing sort mode toggle on Block Grid editor

* [WIP] Further work on Block Grid editor sort-mode

* Added "umb-sort-mode-toolbar" component

* Fixed typo of private method "renderNoting"

* Renamed "sort" property-action to "sort-mode"

* Corrected bad copypasta!

* Renamed "Sort" package to "Sorter"

to include the Sorter controller and maintain backwards-compatibility.

* Code updates based on @copilot feedback

* Fixed circular references

* Removed reference to "sorter/index.ts"

that I'd missed when relocating the package.

* Moved "sorter" back into "core" package

* Moved the "sort" property-action to a combined "property-actions" location

Fixed up other code, use of constants and manifest clarity.

* rename with claude code (#21036)

* rename with claude code

* include property action in name

* renaming

* Rename sortingMode to isSortMode in property sort context

Refactored property sort mode context and related components to use 'isSortMode'

* add jsdocs

* Update vite.config.ts

* no need to export as element

* add tests

* Ordered the tsconfig namespaces

* Reverted the relocation of the "sorter" controller files

* Import ordering

* Reverted some code style tweaks

* Renamed `sortingMode` to `isSortMode`

* Renamed `sortModeEnabled` to `isSortMode`

* Add tests for property sort mode action

* add js docs

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2025-12-04 09:03:58 +00:00
Jacob OvergaardandGitHub 26679d17db build(deps): bumps monaco-editor from 0.54.0 to 0.55.1 (#21054) 2025-12-04 08:51:45 +00:00
Andreas ZerbstandGitHub 7b462c17f9 E2E: QA updated flaky acceptance tests (#21012)
* Updated tests

* Updated tests

* Cleane up

* Bumped version of test helpers

* Updated tests

* Bumped test helpers
2025-12-04 08:26:47 +00:00
cb454372f2 Debug mode: Marks UMB-DEBUG cookie as HttpOnly and Secure (#21032)
* fix: sets profiling cookie to httpOnly and strict in order to run non-secure

* fix: adds extra message to explain when you can set a cookie

* fix: simplify cookie explanation comment in WebProfilerRepository

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: checks that the profiler is actually enabled and/or disabled and warns the user if that is not the case

* Update src/Umbraco.Web.UI.Client/src/assets/lang/en.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 08:55:39 +01:00
84fecd3521 Backoffice: CTRL+Click to open in a new tab should work on Linux (closes #21009) (#21027)
* fix: uses 'href' as property instead of attribute

* build: runs on PR to release branches

* Content references: Avoid requesting references for content that is not yet persisted server side (#21035)

* Avoid requesting references for content that is not yet persisted server side.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor to use condition

* revert

* danish translations

* da translation

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>

* fix: CTRL+Click now opens links in new tab on Linux

The router's anchor click handler incorrectly assumed non-Windows
platforms use Meta (⌘) key for "open in new tab". This broke
CTRL+Click on Linux, which uses CTRL like Windows.

Changed detection from "is Windows" to "is Mac" so Linux correctly
uses CTRL+Click while Mac continues to use Meta+Click.

Also replaced deprecated navigator.platform with navigator.userAgent.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 15:03:18 +00:00
Andy Butland 3472ff9ba3 Bump version to 16.4.1. 2025-12-03 15:38:10 +01:00
577dc06d55 Delivery API: Only add default strategy if delivery API is not registered. (#20982)
* Only add if not already present

* Update src/Umbraco.Cms.Api.Management/DependencyInjection/WebhooksBuilderExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2025-12-03 15:37:03 +01:00
Jacob Overgaard c35fcf181b Merge remote-tracking branch 'origin/release/17.0' 2025-12-03 15:10:47 +01:00
86411e4ae3 Content references: Avoid requesting references for content that is not yet persisted server side (#21035)
* Avoid requesting references for content that is not yet persisted server side.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor to use condition

* revert

* danish translations

* da translation

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-12-03 12:25:06 +00:00
f4771d1495 Delivery API: Only add default strategy if delivery API is not registered. (#20982)
* Only add if not already present

* Update src/Umbraco.Cms.Api.Management/DependencyInjection/WebhooksBuilderExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2025-12-03 12:32:30 +01:00
6104ae60ce Image cropper modal import missing component (#20651)
* Import missing component

* Handle nullable type

* Vertically center image

* Add minimum width for SVG without dimensions

* 100% height until max height

* 100% height minus top/bottom padding

* Revert "100% height minus top/bottom padding"

This reverts commit 67ada4c70f4b75dfcfa2b54ce139ec7465a17ce1.

* Revert "Handle nullable type"

This reverts commit 3130e11a4be83a18b5a7d8c1c24ee23c94d8765d.

* Removed flexbox style

* Fixed circular dependency

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-12-02 17:07:01 +00:00
bcec927e64 Modal: Remove unused uui-dialog element in modal component (#21030)
refactor(backoffice): remove unused uui-dialog element in modal component

Remove dead code that created an unnecessary uui-dialog element inside uui-modal-dialog. The uui-modal-dialog component already manages its own internal dialog element, making the manual creation redundant.

This aligns the dialog implementation with the sidebar implementation pattern, where container elements manage their own internal structure.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 18:04:19 +01:00
Andy Butland 5e1f758117 Merge branch 'release/17.0' 2025-12-02 15:57:09 +01:00
Andy Butland b0e5cd768d Reverted accidental change to Program.cs. 2025-12-02 15:56:30 +01:00
Andy Butland a9d8d13735 Merge branch 'release/17.0'
# Conflicts:
#	tests/Umbraco.Tests.Integration/CompatibilitySuppressions.xml
2025-12-02 15:42:32 +01:00
Niels LyngsøandGitHub 857f2900bb Segments: Fix for processing data for Segments-variants (#21018)
* refactor to load segments before processing incoming data

* clean up

* remove unused segment promise
2025-12-02 15:00:25 +01:00
876fc5fff9 Collection: Introduce Collection Item Ref extension type (#20994)
* Add entity collection item card extension type + default elements

* implement user collection item card

* fix selection events

* map to prop

* add prop/attr for href

* add support for which detail properties to show

* update type import

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/item/entity-collection-item-card/entity-collection-item-card.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* import card in correct file

* Fix event listener binding for selection events

* implement disabled property for collection item cards

* init commit of collection item ref extension

* fix imports

* add element interface

* Implement UmbEntityCollectionItemElement interface in item cards

Added the UmbEntityCollectionItemElement interface to document and user collection item card elements for improved type safety and consistency. Updated type exports to include the new interface.

* Update collection item ref to use uui-ref-node

Replaces the placeholder div with a uui-ref-node component, passing relevant item properties and event handlers. Adds dynamic icon rendering using umb-icon.

* Refactor entity collection item elements to use shared base

Introduces a new abstract base class for entity collection item elements, consolidating shared logic for card and ref variants. Updates card and ref element implementations to extend the new base, and refactors extension manifest interfaces for consistency. This improves maintainability and reduces code duplication.

* use class instead of magic string

* Use ifDefined for href in item card element

* Fix href attribute handling in collection item ref

* Make meta property optional in ManifestEntityCollectionItemBase

* Use ifDefined for href binding in document card

* Fix user card href binding with ifDefined

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-02 13:07:52 +00:00
c612fcc866 Localization: Adds termOrDefault() method to accept a fallback value (#20947)
* feat: adds `termOrDefault` to be able to safely fall back to a value if the translation does not exist

* feat: accepts 'null' as fallback

* feat: uses 'termOrDefault' to do a safe null-check and uses 'willUpdate' to contain number of re-renders

* feat: uses null-check to determine if key is set

* chore: accidental rename of variable

* uses `when()` to evaluate

* revert commits

* fix: improves the fallback mechanism

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-02 11:58:25 +00:00
Niels LyngsøandGitHub c885922a64 Block: open-interaction only available when Content is Editable (#20833)
Only interactive-open area when editable
2025-12-02 10:57:17 +00:00
1cdc15efda Collection: Introduce Collection Item Card extension type (#20954)
* Add entity collection item card extension type + default elements

* implement user collection item card

* fix selection events

* map to prop

* add prop/attr for href

* add support for which detail properties to show

* update type import

* Update src/Umbraco.Web.UI.Client/src/packages/core/collection/item/entity-collection-item-card/entity-collection-item-card.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* import card in correct file

* Fix event listener binding for selection events

* implement disabled property for collection item cards

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-02 10:43:43 +00:00
Kenn JacobsenandGitHub 657ccbd104 Delivery API: Retain the Delivery API login redirect behavior in .NET 10 (closes #21000) (#21023)
* Retain the Delivery API login redirect behavior in .NET 10

* Retrofit fix for backwards compatability
2025-12-02 11:02:18 +01:00
e0999c186b Chore: Move old icons into legacy folder, make new folder for custom. (#20990)
* move legacy icons into a folder

* regenerate icons

* icon compile script for custom

* Reverts "icon-company" to use "building-2" from latest Lucide version

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-12-02 09:49:23 +00:00
da66cbdcf4 Property Editors: Added form control and mandatory support(User, Member, Member Group) (#20672)
* Implement form control for user picker property editor.

* Added form control support to member picker property editor.

* Added form control support to member group picker property editor and removed super.value.

* Reverted max state to infinity.

* Removed console.log inside the render.

* Removed duplicated import.

* Import missing input components in member picker tests

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2025-12-02 07:44:08 +00:00
Andy ButlandandZeegaan 7d0101170e Management API: Return not found from request for content references when entity does not exist (closes #20997) (#20999)
* Return not found when request for content references when entity does not exist.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Move check for entity existence from controller to the service.

* Update OpenApi.json.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Addressed points raised in code review.

* Update OpenApi.json

* Resolved breaking changes.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
(cherry picked from commit da94e0953b)
2025-12-02 13:28:50 +09:00
da94e0953b Management API: Return not found from request for content references when entity does not exist (closes #20997) (#20999)
* Return not found when request for content references when entity does not exist.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Move check for entity existence from controller to the service.

* Update OpenApi.json.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Addressed points raised in code review.

* Update OpenApi.json

* Resolved breaking changes.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-02 13:25:43 +09:00
Andy ButlandandZeegaan 706ac2d8f6 Static files: Fix tree to only provide items from expected folders (closes #20962) (#21001)
* Applies checks for root folders to static file tree service.

* Add integration tests.

* Fix ancestor test.

* Amends from code review.

* Integration test compatibility suppressions.

* Reverted breaking change in test base class.

(cherry picked from commit 84c15ff4d7)
2025-12-02 10:22:15 +09:00
Andy ButlandandGitHub 84c15ff4d7 Static files: Fix tree to only provide items from expected folders (closes #20962) (#21001)
* Applies checks for root folders to static file tree service.

* Add integration tests.

* Fix ancestor test.

* Amends from code review.

* Integration test compatibility suppressions.

* Reverted breaking change in test base class.
2025-12-02 10:20:08 +09:00
Andy ButlandandZeegaan f408d2a1b3 Migrations: Optimise ConvertLocalLinks migration to process data in pages, to avoid having to load all property data into memory (#21003)
* Optimize ConvertLocalLinks migration to process data in pages, to avoid having to load all property data into memory.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Updated obsoletion warning.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
(cherry picked from commit 742de79f46)
2025-12-02 10:18:48 +09:00
742de79f46 Migrations: Optimise ConvertLocalLinks migration to process data in pages, to avoid having to load all property data into memory (#21003)
* Optimize ConvertLocalLinks migration to process data in pages, to avoid having to load all property data into memory.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Updated obsoletion warning.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-02 10:09:54 +09:00
Jacob OvergaardandGitHub 1694e3bad2 Tree: Fix incorrect error notification when deleting last child (closes #20977) (#20985)
* Fix infinite recursion and incorrect error notifications in tree children loading

This commit addresses two critical issues in the tree item children manager:

1. **Infinite recursion vulnerability**: The #resetChildren() method called
   loadChildren(), which could recursively call #resetChildren() again if
   the underlying issue persisted, creating an infinite loop.

2. **Inappropriate error messages**: The "Menu loading failed" notification
   was shown even in legitimate scenarios, such as when deleting the last
   child of a node, where an empty tree is the expected outcome.

Changes made:

- Add ResetReason type ('error' | 'empty' | 'fallback') to differentiate
  between error states and expected empty states

- Extract #loadChildrenWithOffsetPagination() as a terminal fallback method
  that uses only offset pagination and never calls #resetChildren(),
  structurally preventing recursion

- Update #resetChildren() to:
  - Accept a reason parameter to determine whether to show error notification
  - Reset all retry counters (#loadChildrenRetries, #loadPrevItemsRetries,
    #loadNextItemsRetries) to ensure clean state
  - Call #loadChildrenWithOffsetPagination() instead of loadChildren()
  - Only show error notification when reason is 'error'

- Update all call sites of #resetChildren() with appropriate reasons:
  - 'error' when retries are exhausted (actual failures)
  - 'empty' or 'fallback' when no new target is found (may be expected,
    e.g., after deleting items)

The fix makes infinite recursion structurally impossible by creating a
one-way flow: target-based loading can fall back to #resetChildren(),
which calls offset-only loading that never recurses back.

* Fix undefined items array causing tree to break after deletion

This fixes the root cause of issue #20977 where deleting a document type
would cause the tree to "forever load" with a JavaScript error.

The error occurred in #getTargetResultHasValidParents() which called .every()
on data without checking if it was undefined. When the API returned undefined
items (e.g., after deleting the last child), this caused:

TypeError: can't access property "every", e is undefined

The fix adds a guard to check if data is undefined before calling .every(),
returning false in that case to trigger the proper error handling flow.

* Address code review feedback on terminal fallback method

- Change error throwing to silent return for graceful failure handling
- Remove target pagination state updates from offset-only loading method
- Update JSDoc to clarify that method does not throw errors
2025-12-01 20:12:23 +01:00
Andy Butland 35f73a8a31 Migrations: Set a long timeout by default on the migration of system dates (closes #21013) (#21022)
Set a long timeout by default on the migration of system dates.
2025-12-01 19:24:26 +01:00
Andy ButlandandGitHub 24b3f11329 Migrations: Set a long timeout by default on the migration of system dates (closes #21013) (#21022)
Set a long timeout by default on the migration of system dates.
2025-12-01 19:13:55 +01:00
Andy Butland 025a4e056f Merge branch 'release/17.0'
# Conflicts:
#	src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
#	version.json
2025-12-01 19:06:16 +01:00
Andy Butland 822a2fcf70 Migrations: Ensure umbracoPropertyData column casing (#21015)
* Add migration to fix umbracoPropertyData column casing.

* Improve migration with column existence check and logging

- Add ILogger to log when column is renamed
- Check if column exists with incorrect casing before renaming
- Use fluent Rename API instead of raw SQL
- Add XML remarks documentation

?? Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Clarify what old and new column name really is

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: kjac <kja@umbraco.dk>
# Conflicts:
#	src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
2025-12-01 19:01:55 +01:00
34aabb8413 Migrations: Ensure umbracoPropertyData column casing (#21015)
* Add migration to fix umbracoPropertyData column casing.

* Improve migration with column existence check and logging

- Add ILogger to log when column is renamed
- Check if column exists with incorrect casing before renaming
- Use fluent Rename API instead of raw SQL
- Add XML remarks documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Clarify what old and new column name really is

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: kjac <kja@umbraco.dk>
2025-12-01 17:47:31 +00:00
Laura NetoandGitHub 1d59e20daa Delivery API: Missing Member Open API security scheme references (#21020)
Use AddComponent for OpenAPI security scheme registration

Fixes security requirements being serialized as empty objects in the
OpenAPI document by using the document's AddComponent method instead
of directly manipulating the SecuritySchemes dictionary.
2025-12-01 17:24:28 +01:00
Mads RasmussenandGitHub 1c922f34f5 Table Collection View: Update table view icon to 'icon-table' (#20970)
Update table view icon to 'icon-table'

Replaces the 'icon-list' icon with 'icon-table' for all table view manifests across multiple packages to improve consistency and better represent the table view visually.
2025-12-01 16:09:55 +00:00
Mads RasmussenandGitHub 18bbf5609b Data Type Workspace: Enable client mandatory field validation for configuration properties (#20799)
* Add validation property to PropertyEditorSettingsProperty

Introduces a 'validation' field to the PropertyEditorSettingsProperty interface, allowing configuration of mandatory status and custom mandatory messages for property editor settings.

* Pass validation property to umb-property component
2025-12-01 16:03:14 +00:00
0210e942ed Folder Workspace: Support menu expansion and breadcrumbs (closes #20675) (#20712)
* add menu context and breadcrumbs for document type folders

* add menu context and breadcrumbs for media type folders

* add menu context and breadcrumbs for media type folders

* add menu context and breadcrumbs for partial view folders

* add menu context and breadcrumbs for partial view folders

* add menu context and breadcrumbs for script folders

* Register menu structure workspace contexts and breadcrumbs for document blueprints

* fix menu alias

* remove from blueprints

* fix wrong path when navigating from an inner folder to an outer

* remove debugger

* fix structure link between variant to invariant

* fix up path generation

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-12-01 14:00:00 +00:00
bbc0f1f894 Upgrade: Deprecates Mangement API controller for defunct our.umbraco.com version checker (#21011)
* fix: deprecates the upgrade checker

* fix: removes any deprecated UI that no longer has a function for upgrade checks in the backoffice

* chore: generates new api types

* chore: deprecates types

* chore: returns direct task

* docs: explains deprecation

* chore: deprecated model

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-12-01 12:50:51 +00:00
Mole 75b40e79a2 Cache: Add awaits to memory cache rebuilds to fix race conditions (#20960)
* Await rebuilds and fix multiple open DataReaders

* Add additional missing awaits

(cherry picked from commit eaf5960a4d)
2025-12-01 13:46:23 +01:00
09844204b7 History: Take URL objects into consideration when storing Backoffice history (#20986)
* fix: allows URL to be passed to navigator

* Also adds fix to Block workspace

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-12-01 12:29:07 +00:00
Kenn JacobsenandGitHub 1c4b4c90c9 Rendering: Don't use element cache level on snapshot cache level properties (#21006)
Don't use element cache level on snapshot cache level propreties
2025-12-01 12:52:35 +01:00
820c34432a Preview: Fix preview showing published version when Save and Preview is clicked multiple times (closes #20981) (#20992)
* Fix preview showing published version when Save and Preview is clicked multiple times

Fixes #20981

When clicking "Save and Preview" multiple times, the preview tab would show the published version instead of the latest saved version. This occurred because:

1. Each "Save and Preview" creates a new preview session with a new token
2. The preview window is reused (via named window target)
3. Without a URL change, the browser doesn't reload and misses the new session token
4. The stale page gets redirected to the published URL

Solution: Add a cache-busting parameter (?rnd=timestamp) to the preview URL, forcing the browser to reload and pick up the new preview session token. This aligns with how SignalR refreshes work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Improve Save and Preview to avoid full page reloads when preview is already open

When clicking "Save and Preview" multiple times with a preview tab already open, the entire preview tab would reload. This enhancement makes it behave like the "Save" button - only the iframe reloads, not the entire preview wrapper.

Changes:
- Store reference to preview window when opened
- Check if preview window is still open before creating new session
- If open, just focus it and let SignalR handle the iframe refresh
- If closed, create new preview session and open new window

This provides a smoother UX where subsequent saves don't cause the preview frame and controls to reload, only the content iframe refreshes via SignalR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Close preview window when ending preview session

Changes the "End Preview" behavior to close the preview tab instead of navigating to the published URL. This provides a cleaner UX and ensures subsequent "Save and Preview" actions will always create a fresh preview session.

Benefits:
- Eliminates edge case where preview window remains open but is no longer in preview mode
- Simpler behavior - preview session ends and window closes
- Users can use "Preview website" button if they want to view published page

Also removes unnecessary await on SignalR connection.stop() to prevent blocking if the connection cleanup hangs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix preview cookie expiration and add proper error handling

This commit addresses cookie management issues in the preview system:

1. **Cookie Expiration API Enhancement**
   - Added `ExpireCookie` overload with security parameters (httpOnly, secure, sameSiteMode)
   - Added `SetCookieValue` overload with optional expires parameter
   - Marked old methods as obsolete for removal in Umbraco 19
   - Ensures cookies are expired with matching security attributes

2. **PreviewService Cookie Handling**
   - Changed to use new `ExpireCookie` method with explicit security attributes
   - Maintains `Secure=true` and `SameSite=None` for cross-site scenarios
   - Uses new `SetCookieValue` overload with explicit expires parameter
   - Properly expires preview cookies when ending preview session

3. **Frontend Error Handling**
   - Added try-catch around preview window reference checks
   - Handles stale window references gracefully
   - Prevents potential errors from accessing closed window properties

These changes ensure preview cookies are properly managed throughout their
lifecycle and support both same-site and cross-site scenarios (e.g., when
the backoffice is on a different domain/port during development).

Fixes #20981

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Track document ID for preview window to prevent reusing window across different documents

When navigating from one document to another in the backoffice, the preview window reference was being reused even though it was showing a different document. This meant clicking "Save and Preview" would just focus the existing window without updating it to show the new document.

Now we track which document the preview window is showing and only reuse the window if:
1. The window is still open
2. The window is showing the same document

This ensures each document gets its own preview session while still avoiding unnecessary full page reloads when repeatedly previewing the same document.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove updates to ICookieManager and use Cookies.Delete to remove cookie.

* Fix file not found on click to save and preview.

* Removed further currently unnecessary updates to the cookie manager interface and implementation.

* Fixed failing unit test.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-12-01 11:16:35 +00:00
b40ea0df8c Content Type Workspace: Create condition that checks content type uniques. (#20906)
* Created condition for workspace content type unique.

* Changed import.

* Revert import.

* Updated name in the alias example and also import.

* Update src/Umbraco.Web.UI.Client/examples/entity-content-type-condition/index.ts

Co-authored-by: Mads Rasmussen <madsr@hey.com>

* Update src/Umbraco.Web.UI.Client/examples/entity-content-type-condition/workspace-view-unique.element.ts

Co-authored-by: Mads Rasmussen <madsr@hey.com>

* Moved the manifest definition to the manifest file.

* Changed default export.

* Updated example element to render the real GUID.

* Fixed import.

* Replaced CONTENT_WORKSPACE for PROPERTY_STRUCTURE_WORKSPACE context.

* Moved content type unique condition to the content type folder.

* Fixed import.

* final adjustments

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2025-12-01 11:01:09 +01:00
050b37ed1a Installer: Removes unused telemetry functionality (#20995)
* fix: removes the non-functioning installer telemetry and obsoletes all InstallHelper functionality

* fix: deprecates related cookie

* fix: adds ActivatorUtilitiesConstructor for DI

* fix: obsoletes and removes more telemetry functionality

* fix: removes uneeded modifier

* docs: removes docs

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-28 22:21:04 +01:00
f99e9394f8 Culture and Hostnames: Add ability to sort hostnames (closes #20691) (#20826)
* Adding the sorter controller, and fixing some ui elements so you are able to drag the hostname elements around to sort them

* Fixed sorting

* Changed the html structure and tweaked around with the css to make it look better.
Added a description for the Culture section.
Alligned the rendered text to allign better with the name "Culture and Hostnames"

* Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/culture-and-hostnames/modal/culture-and-hostnames-modal.element.ts

Forgot to remove this after I was done testing

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/culture-and-hostnames/modal/culture-and-hostnames-modal.element.ts

Changing grid-gap to just gap

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Removed the disabled and readonly props I added since they are not needed.
Removed the conditional rendering that was attached to the readonly and disabled properties

* Removed the item id from the element and changed css and sorter logic to target the hostname-item class instead

* Updated test

* Bumped helpers

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
Co-authored-by: Andreas Zerbst <andr317c@live.dk>
2025-11-28 10:06:20 +01:00
Andy ButlandandGitHub 9c038bc68b Re-enable package validation (#20964)
* Re-enable package validation.

* Remove unnecessary supressions file.

* Removed unnecessary suppressions.

* Restored and obsoleted all overload.
2025-11-28 09:48:06 +01:00
e6b99938db Delivery API: Only add default strategy if delivery API is not registered. (#20982)
* Only add if not already present

* Update src/Umbraco.Cms.Api.Management/DependencyInjection/WebhooksBuilderExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2025-11-28 08:25:06 +01:00
Zeegaan 5ab93454d9 Bump version 2025-11-28 10:58:04 +09:00
Warren BuckleyandGitHub f44e9328d7 Extensions: Adds all yet unused Lit directives to @umbraco-cms/backoffice/external/lit (closes #20961) (#20963)
* Adds choose directive to @umbraco-cms/backoffice/external/lit

This can then allow choose to be imported like so
import { html, customElement, LitElement, property, css, choose } from '@umbraco-cms/backoffice/external/lit';

* Exports all of Lits directives for @umbraco-cms/backoffice/external/lit

Also puts them in alphabetical order to help add any new ones Lit may add in the future
2025-11-27 15:22:50 +00:00
Jacob Overgaard ec11714b4b Merge remote-tracking branch 'origin/v16/dev' 2025-11-27 15:46:27 +01:00
Lee KelleherandGitHub 615cb76288 Block editors: adds prefix to workspace title (closes #20588) (#20884)
* Adds `$settings` to the block workspace label renderer

* Adds a prefix to the Block workspace title

* Imports tidy-up
2025-11-27 15:39:27 +01:00
Sven GeusensandGitHub c61bcca066 Add Claude memory files for all relevant project files (#20959)
* Regenerate delivery api claud memory file for updated file lines and inclusion of Secure Cookie-Based Token Storage

* Add delivery api memory file

* claude memory file for in memory modelsbuilder project

* Claud memory file for Imagesharp project

* Claude memory file for legacy image sharp project

* Claude memory files for Persistence projects

* Remaining claude memory files
2025-11-27 10:47:19 +01:00
MoleandGitHub eaf5960a4d Cache: Add awaits to memory cache rebuilds to fix race conditions (#20960)
* Await rebuilds and fix multiple open DataReaders

* Add additional missing awaits
2025-11-26 15:02:07 +01:00
Niels LyngsøandGitHub ff8cbb8b81 PropertyGuards: improved argument names and JSDocs (#20949)
improved argument names and JSDocs
2025-11-26 10:44:38 +01:00
Niels LyngsøandGitHub a364c9e86d Content Property: Remove unused 'entityType'-property (#20948)
remove unused property
2025-11-26 10:41:41 +01:00
ce98184178 Log Viewer: Enhances the donut chart to be responsive, link to log search, and show numbers directly (#20928)
* Log Viewer: Refactor log types chart to use Lit repeat directive

- Import and use repeat directive for better performance
- Add _logLevelKeys state property to track log level keys
- Update setLogLevelCount() to populate _logLevelKeys
- Replace .map() with repeat() in render method for legend and donut slices
- Update willUpdate to observe both filter and response changes
- Resolves TODO comment about using repeat directive

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Donut Chart: Add inline numbers and fix tooltip positioning

- Add showInlineNumbers property to optionally display numbers inside slices
- Implement #getTextPosition() method to calculate text position at slice center
- Render SVG text elements when showInlineNumbers is enabled
- Fix tooltip positioning to appear near cursor (changed from x-10, y-70 to x+10, y+10)
- Recalculate container bounds on each mouse move to handle window resize
- Add pointer-events: none to tooltip to prevent mouse interference
- Add CSS styling for slice numbers (user-select: none)
- Enable inline numbers by default in log viewer log types chart

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Donut Chart: Add clickable slices and visible description

- Add href property to donut-slice element for clickable slices
- Wrap SVG paths in <a> tags when href is provided
- Update Circle interface to include href property
- Add showDescription property to optionally display description text
- Render description as visible text below the chart
- Add CSS styling for description text
- Update log-types-chart to build search URLs with log level and date range
- Observe dateRange from context to build accurate search URLs
- Enable clickable slices and visible description in log-types-chart

Now clicking on a donut slice navigates to the search view filtered by that log level and the current date range.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: uses whole link

* Log Viewer: Fix log types chart layout for larger screens

Add media query to switch from column to row layout on screens wider than 768px. This ensures the legend and donut chart are displayed side by side on desktop resolutions instead of stacked vertically.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: improves mock function

* chore: formatting

* fix: ensures the donut chart works responsively

* feat: adds support for SVGAElement in the router

* adds key for description

* chore: adds test data

* feat: displays numbers in the legend instead of the chart

* chore: restores functionality with lower-cased keys

* fix: adds translation to 'log messages'

* chore: removes unused method

* feat: ensures that the log levels follow the generated LogLevelModel enum from the server, which requires to map the keys as JSON camelCase's the keys

* fix: uses correct property

* fix: reverts back to the original behavior to calculate a relative URL (rather than the automatic .toString() that gets a qualified URL)

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: uses fullUrl for router

* fix: properly translates new aria-label

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-26 09:28:44 +00:00
Nhu DinhandGitHub 69e2f8df74 E2E: QA Added acceptance tests for notification emails (#20918)
* Added tests for notification emails for content

* Bumped version

* Updated tests for notification permission in content

* Added appsettings.json for smtp tests

* Added smtp test project

* Updated nightly E2E test pipeline yaml file to run smtp project in the pipeline

* Fixed command to run smtp4dev in Docker

* Fixed pipeline

* Only run smtp tests on Linux

* Debugged

* Debugging

* Added step to stop smtp4dev container

* Debugging

* Updated port

* Reverted tests

* Added more tests for notification emails

* Formatted code
2025-11-26 07:34:36 +00:00
Andy Butland 4b3ce53acf Merge branch 'release/16.4' into v16/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-11-26 07:18:09 +01:00
Andy Butland bd33246525 Merge branch 'release/17.0'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-11-25 15:58:55 +01:00
ef282a5211 docs: Add CLAUDE.md documentation for key .NET projects (#20841)
* docs: Add CLAUDE.md documentation for key .NET projects

Add comprehensive CLAUDE.md files for major Umbraco projects:
- Root CLAUDE.md: Multi-project repository overview
- Umbraco.Core: Interface contracts and domain models
- Umbraco.Infrastructure: Implementation layer (NPoco, migrations, services)
- Umbraco.Cms.Api.Common: Shared API infrastructure
- Umbraco.Cms.Api.Management: Management API (1,317 files, 54 domains)
- Umbraco.Web.UI.Client: Frontend with split docs structure

Each file includes:
- Architecture and design patterns
- Project-specific workflows
- Edge cases and gotchas
- Commands and setup
- Technical debt tracking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update src/Umbraco.Cms.Api.Management/CLAUDE.md

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>

* docs: Update CLAUDE.md with accurate persistence and auth info

- Clarify NPoco is current and fully supported (not legacy)
- Document EF Core as future direction with ongoing migration
- Add secure cookie-based token storage details for v17+
- Update OpenIddict authentication documentation
- Update API versioning (v1.0 and v1.1)
- Minor documentation cleanups (community links, descriptions)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Update src/Umbraco.Web.UI.Client/docs/agentic-workflow.md

* Update src/Umbraco.Web.UI.Client/docs/agentic-workflow.md

* Apply suggestions from code review

* Clarifications and duplicate removal.

---------

Co-authored-by: Phil Whittaker <pjw@umbraco.dk>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Sven Geusens <geusens@gmail.com>
2025-11-25 14:37:49 +00:00
Andy ButlandandGitHub 1240d845d4 Dependencies: Updates some dependencies to latest minor or patch releases (#20953)
Updates some dependencies to latest minor or patch releases for 17.1.
2025-11-25 13:55:15 +01:00
20cfdb9c0a Login Screen: Fix css for login screen dark mode (#20922) (#20946)
* Fix css for login screen dark mode

* Removes the outer-layout wrapper, moving the flexbox to the host

Sets the fallback for `--umb-auth-backdrop` to `--uui-color-surface`

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-11-25 12:17:53 +00:00
Andy Butland ca267047d3 Bumped version to 16.4.0. 2025-11-25 12:32:28 +01:00
Lee KelleherandGitHub 4fe60f360f Block Catalogue: Localizes block-type name/description before render (closes #20890) (#20904)
Block Catalogue: Localizes block-type name/description before render

Fixes #20890.
2025-11-25 10:33:11 +00:00
Jacob OvergaardandGitHub 439c1dccd3 Log Viewer: Adds localization in the Backoffice UI + cleans up unused keys (#20923)
* fix: adds localization to the log viewer

* fix: missing log viewer keys for English

* fix: translations for Danish

* fix: removes unused keys and replaces polling keys

* fix: lowercases values to match what was there before
2025-11-25 10:17:32 +00:00
a41c48ad6c Multi URL Picker: change validation for url and anchor/querystring (#20920)
* Fix validation for url and anchor of multi url picker

* fix codesence warning

* remove redundant validation

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2025-11-25 10:07:21 +00:00
Andy Butland da502e06ae Bump version to 17.0.0. 2025-11-25 09:53:36 +01:00
Andy ButlandandGitHub cf265e248b Examine Management: Allow selection of all available fields in Examine search results, and fix layout issue when not all records have all fields (closes #20878 and #20879) (#20909)
* Allowed selection of all available fields in Examine search results, and fix layout issue when not all records have all fields.

* Updates from code review.
2025-11-24 17:57:10 +00:00
Mads RasmussenandGitHub fd5077d823 Example Docs: Add menu item examples (#20910)
Add menu item registration examples

Introduces example implementations for registering action, link, and entity menu items in the backoffice. Includes manifests and API to demonstrate how to extend the menu system.
2025-11-24 16:32:53 +00:00
3d90fffccd UFM: Update contentName component to respect current backoffice culture. (#20927)
* Updated the content-name element to use the DocumentItemDataResolver.

* Import sorting

* Defaults the entity-type to "document"

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-11-24 16:23:35 +00:00
Jacob Overgaard 8f2532a28a Merge remote-tracking branch 'origin/release/17.0' 2025-11-24 16:32:38 +01:00
Jacob Overgaard bfa3ff4042 Merge remote-tracking branch 'origin/v16/dev' 2025-11-24 16:31:29 +01:00
Jacob Overgaard 0543163817 bumps version to 16.5.0-rc 2025-11-24 16:29:11 +01:00
Jacob Overgaard 72f43a5821 Merge branch 'release/16.4' into v16/dev 2025-11-24 16:28:24 +01:00
aea9034adf Localization: Restores region-specific cultures (#20939) (#20942)
* Adds localization manifests for region-specific cultures

This is to support backwards-compatibility and v13 upgradability.

* Removed `uiCulture` from Vietnamese localizations

since it duplicated the English fallback texts.

* 'en' localization file formatting

* Update src/Umbraco.Web.UI.Client/src/assets/lang/en.ts



---------

Co-authored-by: Lee Kelleher <leekelleher@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 15:27:35 +00:00
Jacob Overgaard 6e6f822761 bumps version to 16.4.0-rc3 2025-11-24 15:24:58 +01:00
Niels LyngsøandGitHub 137aa20a10 Block Editors: avoid discard changes for no changes (Fixes #20680) (#20941)
* ensure Block List only updates if it has an update

* ensures RTE and Grid Block Editor ony updates value if there is a change
2025-11-24 14:04:59 +00:00
2b7efbe861 Localization: Restores region-specific cultures (#20939)
* Adds localization manifests for region-specific cultures

This is to support backwards-compatibility and v13 upgradability.

* Removed `uiCulture` from Vietnamese localizations

since it duplicated the English fallback texts.

* 'en' localization file formatting

* Update src/Umbraco.Web.UI.Client/src/assets/lang/en.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 14:41:24 +01:00
Niels LyngsøandGitHub 4138262a19 Examples: updated naming of example (#20938)
updated naming of example
2025-11-24 12:38:10 +00:00
Niels LyngsøandGitHub ea840bcfde Front-end Example: Initial name example (#20899)
initial name example
2025-11-24 12:37:43 +00:00
9beed532a9 Update Swashbuckle to v10 (#20925)
* Update Swashbuckle to v10

* Regenerate backoffice api client

* Add missing space for consistency

* Simplify nullability check

* Small improvement

Didn't notice that these classes were internal, so tried keeping compatibility, but it wasn't needed.

* Fix failing integration test

* Apply suggestions from code review

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Remove unnecessary comma

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 12:06:03 +01:00
Jacob OvergaardandGitHub 215c4dc540 build(deps): bump @microsoft/signalr to 10.0.0 (#20932) 2025-11-24 10:23:08 +00:00
Jacob OvergaardandGitHub f19aaaee52 build(deps): bump marked to 17.0.1 (#20933) 2025-11-24 10:07:45 +00:00
Andy ButlandandGitHub dc50a6e8c3 Update further dependencies for 17 (#20935)
Update further dependencies.
2025-11-24 09:42:35 +00:00
12611942ff Permissions: Protect GetIdsFromPathReversed against invalid program exception (#20930)
* Updates to protect GetIdsFromPathReversed against invalid program exception.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 10:19:37 +01:00
04f98a758d Log viewer: Improves search functionality and code quality (#20913)
* fix: adds correct fallback for dates to avoid console error

* fix: resolves a TODO by using UmbStringState over rxjs Subject

* Refactor log viewer search to use UmbStringState and improve architecture

- Replace RxJS Subject with UmbStringState to follow Umbraco patterns
- Move debounced search observation to messages list component
  - Only triggers when component is mounted (logs are visible)
  - Prevents unnecessary API calls on other views
- Simplify search input to just update context state
- Add semantic form structure with role="search" for accessibility
- Add visually-hidden submit button for keyboard navigation
- Allow re-running same query via form submission (bypasses debounce)
- Follow same architecture pattern as date range selector

This resolves the TODO to not use RxJS directly and significantly improves
separation of concerns where the data consumer (messages list) owns the
fetching logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add visible refresh button to log viewer search input

- Add refresh button with icon-refresh next to save and clear buttons
- Allows users to re-run search with same query (bypasses debounce)
- Remove form structure that couldn't work due to Shadow DOM boundaries
- Simplify parent component by removing form submission logic
- Keep role="search" for accessibility

The refresh button provides a more discoverable UI than the hidden submit
button approach and avoids Shadow DOM event bubbling issues.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix debouncing by adding local state in search input

- Add local UmbStringState to debounce user input (250ms)
- Only update context filterExpression after debounce
- Remove debouncing from messages list (now handled at input level)
- Saved searches and refresh button still bypass debounce for immediate feedback

This restores the expected debouncing behavior while maintaining the clean
architecture where the messages list triggers searches based on context changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: cleans up in docs

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 08:44:45 +00:00
Nhu DinhandGitHub bb88be9d2e E2E: QA Updated .fixme() acceptance tests (#20919)
* Added steps to wait for upload to complete

* Update tests for content with media picker

* Removed fixme tags

* Updated fixme tests

* Bumped version
2025-11-24 12:56:52 +07:00
Nhu DinhandGitHub 60b886dc9c E2E: Updated the failing Default Config tests (#20818)
* Updated block list tests as the “Add Block” button is hidden after reaching the maximum limit.

* Updated validation option due to UI changes

* Updated tests for current user profile as waitForNetworkToBeIdle() is removed

* Fixed flaky tests

* Bumped version

* Updated tests for current user profile

* Bumped version
2025-11-24 12:54:36 +07:00
Callum WhyteandZeegaan d7231c5435 Preserve existing Examine FieldDefinitionCollection if it already exists (#20931)
* Preserve existing Examine FieldDefinitionCollection if it already exists (#20267)

* Fix missing bracket

* Minor tidy/addition of comments; addition of unit tests.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
(cherry picked from commit 908974c6ac)
2025-11-24 12:47:08 +09:00
908974c6ac Preserve existing Examine FieldDefinitionCollection if it already exists (#20931)
* Preserve existing Examine FieldDefinitionCollection if it already exists (#20267)

* Fix missing bracket

* Minor tidy/addition of comments; addition of unit tests.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-11-24 09:53:38 +09:00
Niels LyngsøandGitHub 488f373fea Properties: Implement container queries (#20832)
implement container queries for properties
2025-11-21 13:10:36 +01:00
35acfcb7e2 Trashbin: introduce a empty trash icon (#20629)
* add empty trash icon and use it for empty trash-bin and delete from trash-bin

* package lock

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-11-21 13:05:49 +01:00
Niels LyngsøandGitHub 2939eb4f81 Bock Type Card: make actions stand clear from thumbnail/color (#20895)
clean up and make actions stand clear from custom background colors/images
2025-11-21 11:19:34 +01:00
netaddicts-councilandGitHub 2f02bee421 Sets the default name for the content listview workspace name to 'Child items' instead or 'Collection' (#20907)
Sets the default name for thecontent listview workspace name to 'Child items' instead of 'Collection' (Fixes #20860)
2025-11-20 16:03:25 +01:00
6a7360aded Member types: Implement containers (#20706)
* Add MemberType/MemberTypeContainer to supported EntityContainer object types

* Implement MemberTypeContainerRepository

* Update and add member type container API endpoints

* Complete server and client-side implementation for member type container support.

* Fix FE linting errors.

* Export folder constants.

* Applied suggestions from code review.

* Updated management API authorization tests for member types.

* Resolved breaking change on copy member type controller.

* Allow content types to be moved to own folder without error.

* Use flag providers for member type siblings endpoint.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-11-20 11:28:03 +01:00
Niels LyngsøandGitHub f70f6d4aba Content Type Designer: Only update tab name on change (#20786)
Do not update tab name on input, as it is inappropriate when having name conflicts
2025-11-20 09:37:22 +00:00
75dd9fab2b Redirect tracking: Ensure redirects with domains are stored with the domain node id prefix (closes #20894) (#20900)
* Ensure redirects with domains are stored with the domain node id prefix.

* Handle removal of self-referencing redirect when domains are used.

* Use entity path to save further queries for retrieving ancestor IDs.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Applied refactoring suggested in code review.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-20 16:30:38 +09:00
2f6fb7e395 Block-grid, Block-list: Fix issue translation in clipboard is missing (#20756) (#20903)
Fix issue translation in clipboard

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2025-11-20 07:14:51 +01:00
Lars-Erik AabechandGitHub 43bdad59b6 Integration Tests: Use empty temp folder for legacy lang config when using integration tests outside core (closes #20888) (#20889)
* Use empty folder under temp as localized text source folder in non umbraco core integration tests.

* Added clarifying comment to the GetLocalizedTextService override for tests
2025-11-20 06:54:35 +01:00
Niels Lyngsø 61a5d26a93 Merge branch 'release/17.0' 2025-11-19 17:10:34 +01:00
Niels Lyngsø e45f232f44 update workspace context example readme 2025-11-19 17:10:04 +01:00
Andy Butland be116436d9 Migrations: Handles rich text blocks created with TinyMCE in convert local links migration and refreshes internal datatype cache following migration requiring cache rebuild (closes #20885) (#20887)
Handles rich text blocks created with TinyMCE in convert local links migration.
Refreshes internal datatype cache following migration requiring cache rebuild.
# Conflicts:
#	src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs
2025-11-19 15:35:48 +01:00
Andy ButlandandGitHub a488d77ce7 Migrations: Handles rich text blocks created with TinyMCE in convert local links migration and refreshes internal datatype cache following migration requiring cache rebuild (closes #20885) (#20887)
Handles rich text blocks created with TinyMCE in convert local links migration.
Refreshes internal datatype cache following migration requiring cache rebuild.
2025-11-19 14:54:12 +01:00
386611bc70 TextBox, TextArea: Message max length validation (close #20710) (#20886)
* fix bug max length messsage

* change localization

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2025-11-19 14:24:32 +01:00
Niels Lyngsø e2a8bea579 TODOs 2025-11-19 09:55:59 +01:00
Engiber LozadaandGitHub e46e65ef22 Content types: Apply text selection when unlocking alias (#20882)
Added requestAnimationFrame for alias text selection.
2025-11-18 16:17:35 +01:00
Nhu DinhandGitHub a59476a043 E2E: QA Updated tests with the .skip tag (#20739)
* Removed skips for tests whose related issues have been fixed.

* Remove skip tags and update tests for content with list view

* Removed skip tags

* Added comment and change to fixme for tests that need to implement later

* Removed skip tag

* Bumped version
2025-11-18 11:37:53 +00:00
c1b3f41f7c TextBox: Data-type validation for max chars (fixes #18817) (#20843)
* configure max chars for textbox

* min 1

* Adds server-side check for text box min and max character validation.

* Applied suggestion from code review.

* Bumped version of test helper

* Fixed test that was creating a text string data type with too large a maximum characters setting.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Nhu Dinh <hnd@umbraco.dk>
2025-11-18 08:16:59 +01:00
Jacob OvergaardandGitHub 92b5d11c95 Backoffice Preview: Adds notice that the site is not real (#20864)
feat: adds notice to the static backoffice site explaining to the reader that the content is not real
2025-11-17 18:31:55 +01:00
Jacob Overgaard b5ffe8930b chore: fixes merge conflict 2025-11-17 17:20:14 +01:00
Jacob Overgaard a89437e309 test: uses a real non-date value for testing 2025-11-17 17:17:59 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b8c31350fb Bump the npm_and_yarn group across 2 directories with 1 update (#20863)
Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Client directory: [js-yaml](https://github.com/nodeca/js-yaml).
Bumps the npm_and_yarn group with 1 update in the /src/Umbraco.Web.UI.Login directory: [js-yaml](https://github.com/nodeca/js-yaml).


Updates `js-yaml` from 4.1.0 to 4.1.1
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

Updates `js-yaml` from 4.1.0 to 4.1.1
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-17 16:01:59 +00:00
Jacob Overgaard bf35477399 chore: fixes merge conflict 2025-11-17 16:59:25 +01:00
Jacob Overgaard 45c8be4bb7 Merge remote-tracking branch 'origin/v16/dev' 2025-11-17 16:40:11 +01:00
Jacob Overgaard aed7505e4b Merge remote-tracking branch 'origin/release/16.4' into v16/dev 2025-11-17 16:39:38 +01:00
Jacob Overgaard 9035f160fe Merge remote-tracking branch 'origin/release/17.0' 2025-11-17 16:37:58 +01:00
Engiber LozadaandGitHub eae35a27ab Block Entry Context: Update the settingsPropertyValueByAlias to observe settings. (#20861)
Replaced content for settings in the settingsPropertyValueByAlias.
2025-11-17 13:54:30 +00:00
Laura NetoandGitHub 6d44b42400 Use dependency track devops task (#20854)
* Replace dependency track bom script with devops task

* Introduce new url variable in order to fix new task uri

The initial variable contained the api path (/api) in the URL.
2025-11-17 14:54:03 +01:00
590a020303 Redact back-office PKCE codes from the server (V16) (#20851)
Redact back-office PKCE codes from the server (#20847)

* Redact back-office PKCE codes from the server

* Update src/Umbraco.Cms.Api.Common/DependencyInjection/HideBackOfficeTokensHandler.cs

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-11-17 11:17:18 +01:00
Niels LyngsøandGitHub b868a349de Block list: ensure block items stay top-aligned when sorting (#20842)
ensure block items stay top-aligned when sorting
2025-11-15 08:32:18 +01:00
43230dfac8 Redirects: Fixes self referencing redirects (closes #20139) (#20767)
* Adding fix for self-referncing redirects for 17

* Using umbraco context on failing tests

* Tests to see if self referencing redirects gets deleted

* Refactoring and adding correct tests.

* Expanding tests for RedirectTrackerTests.cs

* Optimize by only retrieving th list of existing URLs for a content item if we have a valid route to create a redirect for.

* Extract method refactoring, added explanatory comment, fixed warnings and formatting.

* Resolved warnings in RedirectService.

* Minor naming and formatting refactor in tests.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-11-14 16:37:59 +00:00
01b300336b Property Editors: Added form control and mandatory support to editors in picker group(Color, Content, Date, Document, Eye dropper, Multi URL). (#20684)
* Added form control support to color picker.

* Avoid submit when readonly is true.

* Added mandatory support.

* Added form control support to date picker.

* Removed an unused import.

* Added form control and mandatory support to document picker.

* Added form control support to Eye dropper.

* Added. mandatory support for multi url picker also bind inner input in the eye dropper.

* Removed unused import.

* fix update of value

* fixing not needed override of get and set methods

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-11-14 14:04:20 +00:00
EricandGitHub 6b4503cc7b Content Sorting: increase modal size (#20835)
Modal size increase for sorting content
2025-11-14 14:42:30 +01:00
Andy ButlandandGitHub a4438e5b21 Decimal property editor: Flexibly parse decimal value with different separators (closes #20823) (#20828)
* Flexibly parse decimal value with different separators.

* Applied suggestions from code review.
2025-11-14 10:20:12 +09:00
73847d1eff Property Editors: Added form control and mandatory support to editors in rich content group(Code editor, Markdown, Block grid) (#20693)
* Added mandatory support for block grid property editor.

* Added form control and mandatory support to code editor.

* Added form control and mandatory support to markdown editor.

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-11-13 20:57:27 +00:00
Engiber LozadaandGitHub e549217e66 Content Type Designer: Use input-with-alias and implement regex validation for Alias. (#20755)
* Implemented input-with-alias in the content-type-design-editor.

* Added auto-generate-alias property to the input and revert deletion of checkAliasAutoGenerate method.

* Added form-validation-message.

* Added validation to the input-with-alias element to avoid special characters.
2025-11-13 20:42:48 +00:00
Engiber LozadaandGitHub 8b076597b3 Entity Sign: Improve Firefox visibility and add focus support. (#20733)
* Chenged right and left position of the infobox.

* Added focus support to open the modal.

* Moved tabindex out the constructor and added support for enter and space keys.
2025-11-13 20:37:54 +00:00
bbd30363a2 Media Picker: Remove duplicate loaders in media cards. (#20793)
* Removed isLoding condition from the rich media input and let the thumbnail handle the loader.

* Removed unused import.

* change loader and adjust lit property configuration

* update reflect configuration

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-11-13 20:38:32 +01:00
617d301479 Hides the content files that come from the Microsoft.CodeAnalysis.Workspaces.Common package in the web.ui project in 17 (#20825)
* Hide content files

* Update src/Umbraco.Web.UI/Umbraco.Web.UI.csproj

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-13 14:39:51 +00:00
Jacob Overgaard 931041c635 Merge remote-tracking branch 'origin/v16/dev' 2025-11-13 14:19:10 +01:00
Jacob Overgaard 15c6ca7628 Merge remote-tracking branch 'origin/release/16.4' into v16/dev 2025-11-13 14:15:24 +01:00
Mathias HelsengrenandGitHub 714fbf3119 Keyboard navigation: Return to opening element after modal close (#20782)
Removed the detroy from the modelContext.
It being destroyed prevented the uui-button getting into focus again after closing the modal.
2025-11-13 12:55:45 +01:00
Jacob OvergaardandGitHub eeda55c06f Preview: Add validation support to Save and Preview button (closes #20616) (#20805)
* chore(mock): adds missing try/catch around document lookup

* fix: lets the 'save and preview' button extend the 'save' button to follow the same logic in terms of when it enables/disabled - it did not have much logic before

* fix: runs validation from the server when save and previewing to ensure the UI shows what is missing
2025-11-13 11:25:17 +00:00
Andy Butland 597eb58063 Merge branch 'release/17.0'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-11-13 10:48:51 +01:00
b65d2b0ec7 Collection view test: update changes for v17 (#20812)
update extension for collection view test

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2025-11-13 16:00:21 +07:00
f075223412 Relations: Exclude the relate parent on delete relation type from checks for related documents and media on delete, when disable delete with references is enabled (closes #20803) (#20811)
* Exclude the relate parent on delete relation type from checks for related documents and media on delete, when disable delete with references is enabled.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Applied suggestions from code review.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-13 09:32:18 +01:00
Engiber LozadaandGitHub d4d4b8a50a Content Type Designer: Always register root route to support drag-and-drop into empty Generic tab. (#20809)
Always register root route to enable drag-drop on empty Generic tab.
2025-11-13 09:19:33 +01:00
49ba89c22a Move access/refresh tokens to secure cookies (#20779)
* feat: adds the `credentials: include` header to all manual requests

* feat: adds `credentials: include` as a configurable option to xhr requests (and sets it by default to true)

* feat: configures the auto-generated fetch client from hey-api to include credentials by default

* Add OpenIddict handler to hide tokens from the back-office client

* Make back-office token redaction optional (default false)

* Clear back-office token cookies on logout

* Add configuration for backoffice cookie settings

* Make cookies forcefully secure + move cookie handler enabling to the BackOfficeTokenCookieSettings

* Use the "__Host-" prefix for cookie names

* docs: adds documentation on cookie settings

* build: sets up launch profile for vscode with new cookie recommended settings

* docs: adds extra note around SameSite settings

* docs: adds extra note around SameSite settings

* Respect sites that do not use HTTPS

* Explicitly invalidate potentially valid, old refresh tokens that should no longer be used

* Removed obsolete const

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2025-11-13 08:19:42 +01:00
Andy Butland c295271757 Bumped version to 16.4.0-rc2. 2025-11-13 06:39:10 +01:00
139b528bda Database migrations: Support DateOnly and TimeOnly in syntax providers (#20784)
* sql column type map include dateonly and timeonly

* Split Mapper and add check null value

* Minor code tidy resolving a few warnings.

* add spaces

* clean code

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-11-13 11:10:51 +07:00
ca15aadf0e Fix for partial view caches not being cleared when content is publish… (#20794)
* Fix for partial view caches not being cleared when content is published/unpublished

* Update src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* Change logic for clearing partial view cache

* Changed logic to only clear partial cache when content is published/unpublished or trashed

---------

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2025-11-13 09:21:26 +09:00
Andreas ZerbstandGitHub c60cf90ffe E2E: QA added entity picker acceptance tests (#20776)
* Added entity picker settings

* Updated tests

* Updated nightly pipeline

* Updated tests

* Bumped versions

* Fixed indentation

* Added comments

* Cleaned up

* Removed duplicate

* Bumped version

* Updated naming
2025-11-12 10:18:53 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Nhu Dinh
c9fc2f2a19 Bump playwright and @playwright/test in /tests/Umbraco.Tests.AcceptanceTest (#20579)
* Bump playwright and @playwright/test

Bumps [playwright](https://github.com/microsoft/playwright) to 1.56.1 and updates ancestor dependency [@playwright/test](https://github.com/microsoft/playwright). These dependencies need to be updated together.


Updates `playwright` from 1.50.0 to 1.56.1
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.50.0...v1.56.1)

Updates `@playwright/test` from 1.50.0 to 1.56.1
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.50.0...v1.56.1)

---
updated-dependencies:
- dependency-name: playwright
  dependency-version: 1.56.1
  dependency-type: indirect
- dependency-name: "@playwright/test"
  dependency-version: 1.56.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bumped version of test helper

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nhu Dinh <hnd@umbraco.dk>
2025-11-12 13:33:21 +07:00
9ad4a7eeba Adds Clear Clipboard button & logic (#20757)
* Adds new dictionary/localization item for the clipboard dialog clear all prompt

* Removes the wrapping uui-box and moved inside the component itself

* Adds Clear Clipboard button and logic

* Adds uui-box from outer components consuimg this into this component
* Adds a header to uui-box
* Adds a conditional uui-button when we have items in clipboard
* Adds confirm dialog/prompt to ask if user wants to clear all items

* Adds in general_clipboard item to use in the UUI-box header

* Removes extra space & moves the requestItems outside the for loop

* Be a better citizen

Make sure the promise for the modal is caught and we return out early if user explictiy cancels modal or presses ESC

* Cleanup my noisy comments for a re-review

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2025-11-11 11:50:23 +00:00
0858d02172 Single block migration (#20663)
* WiP blocklist migration

* Mostly working migration

* [WIP] deconstructed the migration to prefetch and process all data that requires the old definitions

* Working singleblock migration

* Abstracted some logic and applied it to settings elements too.

* Align class and file name.

* Minor code warning resolution.

* More and better comments + made classes internal where it made sense

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-11-11 11:43:03 +00:00
Andy Butland 524912a893 Fix accidental update to global.json. 2025-11-11 11:37:00 +01:00
Jacob Overgaard 55769b1747 Merge remote-tracking branch 'origin/release/17.0' 2025-11-11 09:51:49 +01:00
Jacob Overgaard 0797a3fa59 Merge remote-tracking branch 'origin/release/16.4' 2025-11-11 09:51:13 +01:00
41582de9d1 Collection view: add tests for create and using collection view (#20667)
* write test for custom collection view test

* add clean

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/CollectionView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2025-11-11 14:46:54 +07:00
Andy ButlandandGitHub cfa32b265a Integration Tests: Avoid asserting on errors for permission tests (#20643)
* Added integration tests for PropertyTypeUsageService and adjusted assert in management API permissions test.

* Commented or fixed management API integration tests verifying permissions where we were asserting on an error response.
2025-11-11 05:59:25 +00:00
Mathias HelsengrenandGitHub d8198d2f5c Accessibility: Adding a label attribute for <uui-button> in news dashboard (#20780)
Added 'label attribute to the uui-button in the umb-news.card.element + Removing the redundant text for uui-button since label attribute is now present
2025-11-11 06:33:31 +01:00
Niels LyngsøandNiels Lyngsø 12b483ff05 Fix block list inline mode (#20745)
* Fix block list inline mode

https://github.com/umbraco/Umbraco-CMS/issues/20618

* Fixed potential runtime errors

* Code cleanup

* Fixed Code Health Review

* Revert some changes

Commented out unused state properties and related code.

* Remove commented-out state property in block workspace view

* fix localization

* no need for question mark after ids, they should be presented as required

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2025-11-10 17:42:16 +01:00
9fa382e84d Fix block list inline mode (#20745)
* Fix block list inline mode

https://github.com/umbraco/Umbraco-CMS/issues/20618

* Fixed potential runtime errors

* Code cleanup

* Fixed Code Health Review

* Revert some changes

Commented out unused state properties and related code.

* Remove commented-out state property in block workspace view

* fix localization

* no need for question mark after ids, they should be presented as required

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
2025-11-10 16:17:30 +00:00
ab51aac5c6 Backoffice Item Pickers: Show error for missing items in 10 picker types (closes #19329, #20270, #20367) (#20762)
* Add errorDetail property to umb-entity-item-ref

Add optional errorDetail property to display additional context
(such as file paths or IDs) in error states. This enhances the
error display to show both the error message and relevant details.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Make _removeItem protected in UmbPickerInputContext

Change #removeItem from private to protected to allow subclasses
to reuse the removal logic while customizing the confirmation dialog.
This enables better extensibility for specialized picker contexts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix static file picker to show error state for missing files

Update umb-input-static-file to observe statuses and render based
on item state (loading, error, success). When a static file is
missing (API returns empty array), displays error state with alert
icon and file path detail using umb-entity-item-ref.

Also adds standalone property support for proper single-item styling.

Fixes #19329

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Show file path in static file remove confirmation dialog

Override requestRemoveItem in UmbStaticFilePickerInputContext to
display the file path instead of "Not found" in the confirmation
dialog when removing missing static files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Show GUID in document picker error state

Display the document GUID as errorDetail when a document is
not found (deleted/gone). This provides useful context for
editors to identify which document was referenced.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Show GUID in document picker remove confirmation dialog

Display the document GUID instead of "Not found" in the remove
confirmation dialog when the document no longer exists. This
provides useful context for editors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: apply the temp model which the context uses

* Refactor: Move requestRemoveItem logic to base UmbPickerInputContext

Eliminated duplicate code across three picker contexts by:
- Adding protected getItemDisplayName() method to base class
- Moving requestRemoveItem implementation to base class
- Removing duplicate implementations from document, member, and static file pickers
- Static file picker overrides getItemDisplayName() to show file path

Net reduction: 19 lines of code (69 removed, 50 added)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Document Type Picker: Show error state for missing items (fixes #20367)

Apply the same error state handling to the document type picker that was
implemented for static files, documents, and members. When a referenced
document type is missing or deleted:

- Show error state with the GUID as errorDetail
- Allow removal with proper confirmation dialog
- Use umb-entity-item-ref for error display
- Use uui-ref-node-document-type for successful items

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Additional pickers: Show error states for missing items in user, language, media-type, member-type, member-group, and user-group pickers

Apply the same error state handling pattern to six additional picker types:
- user-input: Users
- input-language: Languages
- input-media-type: Media types
- input-member-type: Member types
- input-member-group: Member groups
- user-group-input: User groups

All pickers now:
- Observe statuses from UmbRepositoryItemsManager
- Show error state with GUID when referenced item is missing/deleted
- Use umb-entity-item-ref for error display
- Use specialized components (uui-ref-node, umb-user-group-ref, etc.) for successful items
- Allow removal with proper confirmation dialog showing GUID

Maintains code reusability by using the base class requestRemoveItem method
with getItemDisplayName() for consistent error handling across all pickers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Lint: Remove unused 'when' imports from input-media-type and user-group-input

* Refactor: Add #renderItem helper method to all pickers for consistency

- Add #renderItem to user-input (extracted from inline repeat callback)
- Change _renderItem to #renderItem in user-group-input for consistency
- Change _renderItem to #renderItem in input-static-file for consistency

All 10 pickers now use consistent #renderItem helper method pattern,
improving code readability and maintainability as suggested by @nielslyngsoe

* `import` sorting

* Corrected (old) JSDoc typos

* Markup tidy-up

* exported `UmbPropertyEditorUIStaticFilePickerElement` as `element`

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-11-10 12:57:24 +00:00
Niels Lyngsø afec900204 Merge branch 'release/17.0'
# Conflicts:
#	src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs
2025-11-10 12:46:47 +01:00
89989d60ce Templates: Fix "Discard changes?" dialog after creating template with master template (fixes #20262) (#20749)
Moves the _data.updateCurrent() call inside the updateLayoutBlock conditional
in setMasterTemplate(). This prevents spurious change detection when loading
templates from the server, while maintaining proper change tracking when users
actually modify the master template via the UI.

This completes the fix started in PR #20529 which added the updateLayoutBlock
parameter but inadvertently left the data model update outside the conditional.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-10 11:00:43 +00:00
73fd52aeea Login: Added custom validation for missing password and user/email on the login form (#20233)
* Added custom validation for missing password and user/email

* Changed some of the logic behind custom validation, so it now uses aria-errormessage

* fix: imports from src folder instead

* build(deps-dev): bump vite to 7.2.0

* formatting

* fix: moves the form into the login.page.element.ts component to better control submission

* fix: creates elements globally

* fix: adds id back to form

* fix: no need to store references to all form elements

* fix: errormessage should show with password field in a span as well

* fix: checks validity of form

* fix: constructs form in auth.element.ts anyway and append localization to validation and add oninput and onblur

* chore: fixes import paths

* fix: fixes special case where ?status was not reset

* fix: changes wording in english

* fix: removes duplicate en-us keys

* feat: adds ariaLive and role attributes

* fix: always clears the text

* fix: username required validation should switch between username and email

* package-lock.json updated on (re)install

* Renamed SVG eye icon filenames

to be conventional and kebab-cased.

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-11-10 10:21:33 +00:00
Niels LyngsøandGitHub bce85e1e88 Package section: use command icon for migrations, remove prop (#20775)
change icon and remove ability to customize
2025-11-10 09:38:53 +00:00
Andy ButlandandGitHub fcfaff9daa Querying: Restore ability to retrieve all children published in any culture (closes #20760) (#20766)
* Restore ability to retrieve all children published in any culture.

* Fixed typo in test name.
2025-11-10 11:02:10 +09:00
04918ec3d2 Slider property editor: Fix for preset value handling of enableRange (#20772)
Fix config value access in UmbSliderPropertyValuePreset

Updated the `UmbSliderPropertyValuePreset` class to ensure the `.value` property is accessed for configuration items. This change improves the accuracy of retrieving `enableRange`, `min`, `max`, and `step` values, addressing potential bugs in value processing.

Co-authored-by: Luuk Peters <Luuk.Peters@proudnerds.com>
2025-11-09 22:38:16 +01:00
Warren BuckleyandGitHub aae316e17e Localization: Supply the display name to the localization key for the alt and title attributes of the 2FA QR code image (#20770)
Simple fix to supply the display name to the localization key for the 2FA QR Code Image
2025-11-09 13:41:41 +01:00
Andy ButlandandGitHub ca08652a60 Installer: Fix issues with newsletter signup (#20705)
* Add setter to allow handling of requests to subscribe to newsletter on install.

* Correct serialization of newsletter subscription request.

* Fix serialization and use the Umbraco.EmailMarketing service for newsletter signup.

* Remove logging of user when setting telemetry level.

* Applied suggestions from code review.
2025-11-07 14:34:26 +01:00
b866c31105 Property action: Add tests for create and using Property Action UI Extension (#20291)
* add property action tests

* add extension property action code

* remove extension registry config

* update helper version

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/PropertyAction.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/PropertyAction.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/AdditionalSetup/App_Plugins/my-property-action/write-property-action.api.js

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/AdditionalSetup/App_Plugins/my-property-action/read-property-action.api.js

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* change tab space size

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2025-11-07 15:02:21 +07:00
Andy ButlandandGitHub 7162c458b1 Fix memory leak with IOptionsMonitor.OnChange and non-singleton registered components (closes #20709 for 16/17) (#20723)
* Fix memory leak with IOptionsMonitor.OnChange and non-singleton registered components.

* Dispose disposable data editors in ValueEditorCache.

* Removed unnecessary refactoring and clarified code comments.
2025-11-06 17:16:01 +01:00
Niels LyngsøandGitHub f4a7a2d9be Reset password localization + format (#20750)
localizations + format
2025-11-06 10:43:46 +00:00
Nicklas KramerandGitHub 3ab12e9b59 Migrations: Fixes migrations from 13 to 17. Media Folder without Collection & Last Synced Table not existing. (#20743)
* Creating and adding new migration. And fixing another small bug.

* Adding XML Header and renaming to a more clearly defined name
2025-11-06 09:40:29 +00:00
Niels LyngsøandGitHub f11b8ffae9 User Workspace: localize password mismatch feedback (#20747)
localize
2025-11-06 09:01:51 +00:00
e155fdff58 Block Custom View: Add tests for create and using block custom view (#20472)
* add test for block custom view

* update format code

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/BlockCustomView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/BlockCustomView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/BlockCustomView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/BlockCustomView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* fix some name test

* add new test for block custom view

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2025-11-06 15:57:55 +07:00
Andy ButlandandGitHub 7502a38033 Dependencies: Update dotnet sdk and node development dependency to latest secure version of current major (16) (#20734)
* Update dotnet sdk and node development dependency to latest secure version of current major.

* Update package-lock.json.
2025-11-05 20:02:11 +01:00
Jacob OvergaardandGitHub 594c3f4eac Rich Text Editor: The media picker skips the "edit media" dialog when editing an image (closes #20066) (#20740)
* fix: Tiptap Media Picker: Skip media picker modal when editing existing images

Fixes the media picker workflow to match v13 behavior where clicking
an existing image directly opens the alt text/caption editor instead
of forcing users to re-select the same image from the media library.

Also fixes caption text extraction to properly read from the figcaption
node using Tiptap's NodeSelection API instead of unreliable attribute-based
approach.

Changes:
- Skip media picker when currentMediaUdi exists (lines 77-92)
- Extract caption from NodeSelection.node using descendants() (lines 55-73)
- Add NodeSelection export to tiptap externals for proper typing

* Refactor: Extract nested logic from media picker execute method

Reduces cyclomatic complexity from 15 to 1 by extracting conditional
logic into focused private helper methods. Addresses CodeScene warnings
for complex method and nested conditionals (bumpy road smell).

Created helper methods:
- #extractMediaUdi, #extractCaption, #findFigcaptionText
- #getMediaGuid, #updateImageWithMetadata

No functional changes - improves maintainability and testability.
2025-11-05 14:51:16 +00:00
72d7ed438f Property Editors: Hide "add button" when maximum configuration is 1 (fixes #20407) (#20738)
Hide add button when max 1

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
2025-11-05 12:12:04 +00:00
Mathias HelsengrenandGitHub 297c5d3824 Header: Adjusted button focus border color contrast (#20562)
Made use of the uui-button outline overwrite to change the focus border color to be the contrast color of the header.
2025-11-05 11:04:59 +00:00
Nhu DinhandGitHub e8f2bb33d7 E2E: QA Fixed the failing tests due to the recent UI changes (#20576)
* Added skip tag for the failing tests due to the issues and added waits for the flaky tests

* Commentted code as the reference items displays randomly

* Bumped version

* Added more waits to avoid the flaky tests

* Updated tests for setting culture and hostnames since the first content already has the default domain

* Fixed flaky tests

* Updated tests since the reload step is flaky

* Added more waits for the flaky tests in Windows

* Need to publish first document before set domain for second document

* Make permission tests run in the pipeline

* Added step to ensure the rollback action is completed

* Reverted npm command

* Added skip tag for the permission tests

* Fixed test for the culture and hostname permission

* Removed waits as it is includes in test helper

* Fixed test for adding a media in RTE Tiptap property editor

* Updated test helper function to avoid the flaky tests releated to block

* Added more waits to ensure image uploaded

* Bumped version

* Bumped version

* Reverted

* Reverted code

* Bumped version of test helper

* Bumped version

* Reverted code

* Added more waits to avoid flaky tests

* Added more waits

* Updated nightly pipeline: remove v17/dev, run different app setting tests by default and not run Relation Type in Linux as they are too flaky

* Added more waits

* Added npm command for testWindows

* Added more waits after creating a folder
2025-11-05 15:54:09 +07:00
Jacob Overgaard 5739049f90 Merge remote-tracking branch 'origin/v16/dev' 2025-11-04 14:09:18 +01:00
Jacob Overgaard 4e74dbf218 Merge branch 'release/16.4' into v16/dev 2025-11-04 14:07:30 +01:00
Jacob OvergaardandGitHub fa5c53b571 Auth: Cleans up stale or completed auth details from storage (#20725)
* fix: cleans up stale PKCE keys after auth regardless of success or error

* fix: cleans up stale PKCE data on logout
2025-11-04 11:31:34 +00:00
2b8146f72d Media: Add protection to restrict access to media in recycle bin (closes #2931) (#20378)
* Add MoveFile it IFileSystem and implement on file systems.

* Rename media file on move to recycle bin.

* Rename file on restore from recycle bin.

* Add configuration to enabled recycle bin media protection.

* Expose backoffice authentication as cookie for non-backoffice usage.
Protected requests for media in recycle bin.

* Display protected image when viewing image cropper in the backoffice media recycle bin.

* Code tidy and comments.

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Introduced helper class to DRY up repeated code between image cropper and file upload notification handlers.

* Reverted client-side and management API updates.

* Moved update of path to media file in recycle bin with deleted suffix to the server.

* Separate integration tests for add and remove.

* Use interpolated strings.

* Renamed variable.

* Move EnableMediaRecycleBinProtection to ContentSettings.

* Tidied up comments.

* Added TODO for 18.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-04 07:39:44 +00:00
Jacob Overgaard b502e29d51 Merge remote-tracking branch 'origin/release/17.0' 2025-11-04 08:25:04 +01:00
Andreas ZerbstandGitHub 76fed82e91 E2E: QA cherry picked acceptance tests updates from 17 (#20714)
* Updated tests

* Bumped version

* Added v16 to nightly e2e run
2025-11-04 08:23:04 +01:00
Lee KelleherandGitHub c1a8500f12 Tiptap RTE: Localizes property editor UI label (removes "[Tiptap]" from label) (closes #20439) (#20713)
* Localized RTE property-editor UI label, removing "[Tiptap]"

* Updated acceptance test

* Localized the button label in the data-type and property-editor picker modals

* Based on @copilot suggestion, localized the property-editor UI label in the other places
2025-11-03 11:49:55 +00:00
cfa530487b Property Editors: Add mandatory support to Number Range (Refactor). (#20570)
* Added mandatory property to number range property editor and bind it to the inner input.

* Added mandatory message support.

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2025-11-03 10:56:37 +01:00
Rick ButterfieldandAndy Butland 43ac32282c Preview: Add allow-forms to iframe sandbox attributes (#20701)
Add 'allow-forms' to iframe sandbox attributes
2025-10-31 13:37:35 +01:00
Rick ButterfieldandGitHub 4fc79ad1f8 Preview: Add allow-forms to iframe sandbox attributes (#20701)
Add 'allow-forms' to iframe sandbox attributes
2025-10-31 13:34:36 +01:00
96ecef0a92 Performance: Request cache referenced entities when saving documents with block editors (#20590)
* Added request cache to content and media lookups in mult URL picker.

* Allow property editors to cache referenced entities from block data.

* Update src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add obsoletions.

* Minor spellcheck

* Ensure request cache is available before relying on it.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: kjac <kja@umbraco.dk>
2025-10-31 12:41:46 +01:00
Laura Neto 5e87dead44 Task: Dependency track (#20670)
* Generate BOM files on build

* Upload BOM to Dependency Track

* Move Backoffice BOM generation to right after install

The build and/or pack steps are deleting files that are needed for the BOM to be generated properly.

* Split the BOM uploads into different jobs

* Fix wrong usage of parameters

* Move order of dependency track stage

* Fix wrong umbracoVersion value

* Small fixes

* Log curl response headers

* Correct version sent to dependency track

* Adjusted curl flags

* Fix bom file path

* Fix dotnet bom file name

* Add Login UI to dependency track

* Generate BOM for E2E Tests

* Move dependency track stage

* Move acceptance test .env generation to e2e install template

Needed as the post install script is expecting this to exist.

* Use major version if public release

* Missing ')'

* Reverted npm install command changes in static assets project
2025-10-31 12:11:32 +01:00
Niels LyngsøandNiels Lyngsø b4220a4d80 Collection children: A slim navigation of collection children + higher take above target (#20641)
* enforce update of children when collection

* only load one above and below collection children

* take 50 above a target for default experience

* revert reset target

* remove old impl
2025-10-31 10:54:37 +01:00
Laura NetoandGitHub 973a9573cc Task: Dependency track (#20670)
* Generate BOM files on build

* Upload BOM to Dependency Track

* Move Backoffice BOM generation to right after install

The build and/or pack steps are deleting files that are needed for the BOM to be generated properly.

* Split the BOM uploads into different jobs

* Fix wrong usage of parameters

* Move order of dependency track stage

* Fix wrong umbracoVersion value

* Small fixes

* Log curl response headers

* Correct version sent to dependency track

* Adjusted curl flags

* Fix bom file path

* Fix dotnet bom file name

* Add Login UI to dependency track

* Generate BOM for E2E Tests

* Move dependency track stage

* Move acceptance test .env generation to e2e install template

Needed as the post install script is expecting this to exist.

* Use major version if public release

* Missing ')'

* Reverted npm install command changes in static assets project
2025-10-31 10:53:57 +01:00
66409b9ebd Performance: Request cache referenced entities when saving documents with block editors (#20590)
* Added request cache to content and media lookups in mult URL picker.

* Allow property editors to cache referenced entities from block data.

* Update src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add obsoletions.

* Minor spellcheck

* Ensure request cache is available before relying on it.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: kjac <kja@umbraco.dk>
2025-10-31 10:49:26 +01:00
Nathan WoulfeandGitHub f27fb58e13 box-sizing to ensure height is correct (#20694) 2025-10-31 06:42:45 +01:00
Mads RasmussenandGitHub b8cb198a1a Document Recycle Bin: Remove non-relevant entity bulk actions (closes #20677) (#20685)
Add 'not trashed' condition to document bulk actions

Introduces the UMB_ENTITY_IS_NOT_TRASHED_CONDITION_ALIAS to various document-related bulk action manifests, ensuring actions like duplicate, move, publish, unpublish, and trash are only available for entities that are not already in the recycle bin.
2025-10-30 13:41:20 +01:00
5032b25e3c Icon picker: Better title for icon colors (#20649)
* Better title for icon colors

* Add name for legacy colors

* Translations of colors

* Fixed import, adding missing colour, added Italian translations.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-10-30 13:34:58 +01:00
3d24f0a51e Implementing an inline toggle button to show/hide password. (#20611)
* Implimented an inline toggle button to show/hide your password, also changed the css to accommodate these changes

* Cleaned the css

Added the svg's to their own const for easy reuse

Added localization for the arialabel on the button

Seperated the createFormLayoutItem so there is a seperate for the password input

Moved all the conditional logic in the onclick event to fit inside one if/else statement

* Removed old logic that added a 100ms timeout that would sometimes be enough for localization to load, and replaced it with a function.
The function will try and resolve the promise by checking if the localize.terms methods returns a changed value, if not then it retries every 50ms or untill it hits a max retry of 40/2 seconds.

* Re adding the hide for -ms-reveal to support Microsoft Edge browsers

* Removed a console.log

* Alligned the button behavior so it fits better with what we have in the uui libary.
Now the button is always visible instead of appearing  on hover or when in focus

* Update src/Umbraco.Web.UI.Login/src/auth.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Login/src/auth.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @iOvergaard

* Apply suggestion from @iOvergaard

* Adding the requested changes via my own fork (#20664)

Changed the logic for waitForLocallization Added the svg's as files that are imported instead of having the raw svg in the code

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-30 11:56:15 +01:00
Jacob Overgaard 1c6d4f360d bumps package.json version to 17.1.0-rc 2025-10-30 11:50:19 +01:00
Jacob Overgaard cdf0e5b3b3 Merge remote-tracking branch 'origin/v17/dev' 2025-10-30 11:49:08 +01:00
Niels Lyngsø 837a56652f Merge branch 'release/17.0' into v17/dev
# Conflicts:
#	version.json
2025-10-29 20:04:40 +01:00
7af67d2944 Have to control of the state store navigation for custom sections or … (#20637)
* Have to control of the state store navigation for custom sections or overrides

* revert wording

* move logic and update comment

---------

Co-authored-by: Lucas Bach Bisgaard <lucas.bisgaard@kraftvaerk.com>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-10-29 20:00:36 +01:00
Jacob Overgaard ce59537006 build: updates lockfile 2025-10-29 11:40:10 +01:00
Jacob Overgaard f87e15b941 build: adds back the ^ missing from openapi-ts to allow newer versions to be used 2025-10-29 11:38:44 +01:00
Andy ButlandandGitHub e7ccfaaaac Routing: Added method to IDocumentUrlService for retrieving document key from URI (closes #20666) (#20673)
Added method to IDocumentUrlService for retrieving document key from URI.
2025-10-29 09:47:17 +01:00
Andy Butland 1f82bdde3d Merge branch 'release/16.3.4'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-10-29 06:45:38 +01:00
8733230762 Property Editors: Added form control and mandatory support to editors in common group(Number, Tags, Slider). (#20659)
* Added mandatory support to property-editor-ui-number.

* Added form control to property-editor-ui-tags

* Added validator to the slider when value is missing and support for mandatory and mandatory message.

* Removed unnecessary ternary.

* Removed white space lit error.

* Fix tags input to handle undefined items array

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2025-10-28 12:33:29 +00:00
Andy Butland 498bb5ee24 Merge branch 'main' into v17/dev 2025-10-28 13:32:23 +01:00
0d2393d866 Caching: Resolves publish and install issues related to stale cached data retrieval (closes #20539 and #20630) (#20640)
* Request cache published content creation with version.

* Reload memory cache after install with package migrations.

* Improve message on install for database cache rebuild.

* Update src/Umbraco.Infrastructure/Install/MigrationPlansExecutedNotificationHandler.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Relocated memory cache refresh after package install from notification handler to unattended upgrader.

* Fix construtor breaking change

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
2025-10-28 13:26:26 +01:00
bea21d7b99 Caching: Resolves publish and install issues related to stale cached data retrieval (closes #20539 and #20630) (#20640)
* Request cache published content creation with version.

* Reload memory cache after install with package migrations.

* Improve message on install for database cache rebuild.

* Update src/Umbraco.Infrastructure/Install/MigrationPlansExecutedNotificationHandler.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Relocated memory cache refresh after package install from notification handler to unattended upgrader.

* Fix construtor breaking change

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
2025-10-28 12:25:13 +00:00
Niels Lyngsø cee730517c Merge branch 'main' into v17/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/content/property-type/workspace/views/settings/property-workspace-view-settings.element.ts
2025-10-28 11:20:03 +01:00
Andy Butland 3dc65c48b3 Bump package-lock.json to 16.3.4. 2025-10-28 09:58:31 +01:00
Niels LyngsøandAndy Butland 18ab333afc Hotfix: Implement a specific sorting method for statuses as the existing has … (#20609)
Implement a specific sorting method for statuses as the existing has to support deprecated implementation of custom getUnique method
2025-10-28 09:15:17 +01:00
Niels LyngsøandAndy Butland fd91f88a7e Item Repository: Sort statuses by order of unique (#20603)
* utility

* ability to replace

* deprecate removeStatus

* no need to call this any longer

* Sort statuses and ensure not appending statuses, only updating them
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts
2025-10-28 09:15:05 +01:00
Andy Butland 13c164d81f Bump version to 16.3.4. 2025-10-28 08:58:03 +01:00
Andy ButlandandGitHub f33eb3f678 Media types: Handle null configured file extensions when populating allowed media types (closes #20620) (#20635)
* Handle null configured file extensions when populating allowed media types.

* Added clarifying comment.
2025-10-27 13:42:48 +01:00
Jan SkovgaardandSebastiaan Janssen e893682723 Don't call generateAlias on #onAliasChange()
Currently it's not possible to use characters like "_" and "-" in aliases due to this check - At least that is was @nul800sebastiaan told me 😇

Suggested fix for #20622
2025-10-25 10:47:56 +02:00
d9cdf03442 Preview: Allows changing the preview environment inside the preview app, and other UX changes that enhance the experience (#20598)
* Preview Device: refactored config

Fixed "flip" icon style.

Removed "shadow" as unnecessary.

Renamed "className" to "wrapperClass" to be descriptive.

* Preview element CSS refinement

* Preview element: load in private extensions

* Added "Preview Environments" preview-app

Made `unique`, `culture` and `segment` observable in the context.

* Aligned preview-app design

with `hidden` attribute and design consistency.

* Created "Preview" package

* Relocated "Preview Apps" and Context to the new package

* Deprecated `UmbDocumentPreviewRepository` (for v19)

as the methods have moved to `UmbPreviewRepository`.

* Removed Preview Sessions event listeners

* Changed localization from "End" to "Exit"

* chore: consumes context only when needed

* feat: uses the UmbPreviewRepository instead

* feat: adds localization to errors and ensures the function does not randomly throw

* feat: prevents creating a new repository for every click

* feat: prevents potential memory leak by adding a signal to the events added to each iframe update

* feat: adds a custom interface to prevent typescript errors

* feat: ensures new string states are checked properly

* docs: adds comment to avoid confusion

* feat: sets up scaling once per iframe load rather than on each update

* fix: ensures that you can go back to the default segment again

* feat: closes popovers when clicking on the iframe (losing blur) and if selecting an item (expect for devices)

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2025-10-24 08:29:22 +00:00
d9c201e3d1 docs: Add backoffice preview URL to README files (#20623)
* docs: Add backoffice preview URL to README files

Added links to https://backofficepreview.umbraco.com/ in both the main repository README and the Umbraco.Web.UI.Client package README to make the live backoffice preview easily discoverable.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: fix link

* Update .github/README.md

Co-authored-by: Andy Butland <abutland73@gmail.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-10-24 08:36:34 +02:00
Andy Butland a5fcfc231d Merge branch 'main' of https://github.com/umbraco/Umbraco-CMS 2025-10-24 06:44:08 +02:00
Andy Butland 6ba03a48c8 Merge branch 'release/16.3.3'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-10-24 06:43:55 +02:00
8434c7d0cb Icon Picker: Fix empty selection allowed on mandatory fields and add validation. (#20536)
* Not show the empty tile when filtering is active.

* Added mandatory property to the icon picker.

* Avoid deselecting the icon on second click when not showing the empty option.

* Extends the form control mixin to the icon picker.

* Used super.value.

* Support mandatory from settings config.

* Removed mandatoryConf.

* remove requestUpdate

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-10-23 13:49:14 +00:00
Niels Lyngsø 67d1ac3b94 Merge branch 'main' into v17/dev 2025-10-23 14:44:24 +02:00
Mads RasmussenandGitHub e482976a9d User And User Group Workspace: Make views extendable (#20548) (#20617)
* implement user details as a workspace view

* register user group details as a workspace view
2025-10-23 14:43:49 +02:00
Bjarne FyrstenborgandGitHub 3854b2bd53 Block List: Remove bold label from inline editing (#20437)
Remove bold label from block list inline editing
2025-10-23 14:32:37 +02:00
Niels Lyngsø 1d8cadbeee Merge branch 'main' into v17/dev 2025-10-23 13:42:30 +02:00
Niels Lyngsø 602ad420bd Merge branch 'release/17.0' into v17/dev
# Conflicts:
#	version.json
2025-10-23 13:40:35 +02:00
dependabot[bot]andJacob Overgaard 08d217360e Bump vite from 7.1.9 to 7.1.11 in /src/Umbraco.Web.UI.Login
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.1.9 to 7.1.11.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.11/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.11
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-23 12:05:29 +02:00
Lee KelleherandGitHub 9cc2df7acd Preview: Removes sessions (#20561)
Removes preview sessions concept

Fixes #19443 and #19471.

The implementation of exiting sessions was a design flawed.
The v13 feature worked due to an implementation bug.

Exiting preview mode should be a deliberate action by the user.
2025-10-23 11:47:50 +02:00
Sebastiaan JanssenandGitHub b762135554 Exclude 'release/no-notes' from release labels 2025-10-23 11:21:25 +02:00
Andy Butland 644334c63b Trees: Restore backward compatibility for file system based tree controllers (closes #20602) (#20608)
* Restore backward compatibility for file system based tree controllers.

* Aligned obsoletion messages.
2025-10-22 16:43:12 +02:00
Andy Butland a09e1777c4 Migrations: Use reliable GUID to check for existence of data type when creating (#20604)
* Use reliable GUID to check for existence of data type in migration.

* Retrieve just a single field in existence check.
2025-10-22 16:43:04 +02:00
Andy Butland 9cb59fe1b4 Bumped version to 16.3.3. 2025-10-22 16:42:12 +02:00
Andy Butland 7dcf329d2c Merge branch 'main' into v17/dev 2025-10-22 16:27:09 +02:00
Andy ButlandandGitHub 6bc498ad41 Trees: Restore backward compatibility for file system based tree controllers (closes #20602) (#20608)
* Restore backward compatibility for file system based tree controllers.

* Aligned obsoletion messages.
2025-10-22 14:20:20 +00:00
Andy Butland c422a9ea6a Merge branch 'main' into v17/dev 2025-10-22 15:15:18 +02:00
f88e28d642 Filesystem: Prevent tree showing other filetypes than the supported ones (#20567)
* Added check to only find .css files in FileSystemTreeServiceBase.cs

* Marking GetFiles as virtual and overriding it in StyleSheetTreeService.cs to only find .css files

* Redone tests to fit new format

* Fix tests to use file extensions

* Adding file extensions to all other relevant tests

* Adding file filter to remaining trees

* Adding tests to ensure invalid filetypes wont show

* Encapulation and resolved minor warnings in tests.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-10-22 15:12:39 +02:00
leekelleher 924af4b565 Merge branch 'main' into v17/dev
# Conflicts:
#	src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs
#	src/Umbraco.Web.UI.Client/src/apps/preview/preview.context.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts
2025-10-22 13:33:45 +01:00
Mads RasmussenandNiels Lyngsø 194fee7c91 Use tryExecute for delete API call
Replaces direct await of #delete with tryExecute to improve error handling in the delete method of UmbManagementApiDetailDataRequestManager.
2025-10-22 14:31:41 +02:00
Niels LyngsøandGitHub 4a65f56d9d Hotfix: Implement a specific sorting method for statuses as the existing has … (#20609)
Implement a specific sorting method for statuses as the existing has to support deprecated implementation of custom getUnique method
2025-10-22 11:57:09 +00:00
Sven GeusensandGitHub 62c1d44a5d Webhooks: Register OutputExpansionStrategy for webhooks if Delivery API is not enabled (#20559)
* Register slimmed down OutputExpansionStrategy for webhooks if deliveryapi is not enabled

* PR review comment resolution
2025-10-22 13:46:56 +02:00
Andy Butland c2eea5d6cc Populate IncludeDescendants on ContentPublishedNotification when publishing branch (forward port of #20578). 2025-10-22 13:37:19 +02:00
Niels Lyngsø 21bf23b67d Dictionary: Fix shortcut Ctrl + S not saving dictionary items (#20605)
* switched event listener from 'change' to 'input'

* Update workspace-view-dictionary-editor.element.ts
2025-10-22 12:37:13 +02:00
Andy ButlandandGitHub 48759b9852 Migrations: Use reliable GUID to check for existence of data type when creating (#20604)
* Use reliable GUID to check for existence of data type in migration.

* Retrieve just a single field in existence check.
2025-10-22 10:21:42 +00:00
Niels Lyngsø 298db76cb1 Merge branch 'release/17.0' into v17/dev 2025-10-22 11:55:14 +02:00
Niels Lyngsø 79639c0571 Item Repository: Sort statuses by order of unique (#20603)
* utility

* ability to replace

* deprecate removeStatus

* no need to call this any longer

* Sort statuses and ensure not appending statuses, only updating them
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts
2025-10-22 11:52:09 +02:00
Jacob Overgaard 44d52392b5 Merge branch 'release/17.0' into v17/dev 2025-10-22 09:50:45 +02:00
Andy Butland 0792e4358b Merge branch 'release/16.3.2'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-10-22 07:11:02 +02:00
leekelleher 4717264e10 Merge branch 'release/17.0' into v17/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/core/recycle-bin/entity-action/restore-from-recycle-bin/restore-from-recycle-bin.action.ts
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
2025-10-21 16:11:22 +01:00
Jacob Overgaard caeb3454e1 build(dev): adds umbracoapplicationurl to vscode launch params 2025-10-21 16:22:57 +02:00
Jacob Overgaard 942ccc82d9 docs: Add 'Running Umbraco in Different Modes' section to copilot-instructions 2025-10-21 16:22:36 +02:00
Andy Butland 8aa9dc8f19 Hybrid Cache: Resolve start-up errors with mis-matched types (#20554)
* Be consistent in use of GetOrCreateAsync overload in exists and retrieval.
Ensure nullability of ContentCacheNode is consistent in exists and retrieval.

* Applied suggestion from code review.

* Move seeding to Umbraco application starting rather than started, ensuring an initial request is served.

* Tighten up hybrid cache exists check with locking around check and remove, and use of cancellation token.
2025-10-21 15:27:15 +02:00
Andy Butland 5488c77e0e Bumped version to 16.3.2. 2025-10-21 15:26:29 +02:00
Andy ButlandandGitHub daace4b4a0 Publishing: Resolve exceptions on publish branch (#20464)
* Reduce log level of image cropper converter to avoid flooding logs with expected exceptions.

* Don't run publish branch long running operation on a background thread such that UmbracoContext is available.

* Revert to background thread and use EnsureUmbracoContext to ensure we can get an IUmbracoContext in the URL providers.

* Updated tests.

* Applied suggestion from code review.

* Clarified comment.
2025-10-21 12:05:10 +02:00
Andy ButlandandGitHub 1ceec183a3 Media: Fixes SQL error to ensure database relation between user group media start folder and deleted media item is removed (closes #20555) (#20572)
Fixes SQL error to ensure database relation between user group media start folder and deleted media item is removed.
2025-10-21 11:38:01 +02:00
Andy ButlandandGitHub 81a8a0c191 Hybrid Cache: Resolve start-up errors with mis-matched types (#20554)
* Be consistent in use of GetOrCreateAsync overload in exists and retrieval.
Ensure nullability of ContentCacheNode is consistent in exists and retrieval.

* Applied suggestion from code review.

* Move seeding to Umbraco application starting rather than started, ensuring an initial request is served.

* Tighten up hybrid cache exists check with locking around check and remove, and use of cancellation token.
2025-10-21 09:57:29 +02:00
ae41438a36 Tiptap RTE: Allow removal of unregistered extensions (#20571)
* Tiptap toolbar config: enable removal of unregistered extensions

* Tiptap statusbar config: enable removal of unregistered extensions

* Tiptap toolbar config: Typescript tidy-up

* Tiptap toolbar sorting amend

Removed the need for the `tiptap-toolbar-alias` attribute,
we can reuse the `data-mark`.

* Tiptap extension config UI amend

If the extension doesn't have a `description`,
then add the `alias` to the title/tooltip, to give a DX hint.

* Tiptap toolbar: adds `title` to placeholder skeleton

* Added missing `forExtensions` for Style Select and Horizontal Rule toolbar extensions

* Update src/Umbraco.Web.UI.Client/src/packages/tiptap/property-editors/toolbar-configuration/property-editor-ui-tiptap-toolbar-configuration.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/Umbraco.Web.UI.Client/src/packages/tiptap/property-editors/statusbar-configuration/property-editor-ui-tiptap-statusbar-configuration.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-21 07:28:01 +00:00
dependabot[bot]andJacob Overgaard 5337c38f2c Bump vite from 7.1.9 to 7.1.11 in /src/Umbraco.Web.UI.Client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.1.9 to 7.1.11.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.11/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.11
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-21 09:13:34 +02:00
Nhu DinhandGitHub 7751e40ba8 E2E: QA Fixed the flaky tests related to publishing content with image cropper (#20577)
Added more waits
2025-10-21 08:50:13 +02:00
Lee KelleherandGitHub d5a2f0572e Preview: Redirect to published URL on exit (#20556)
* Preview Exit: Gets the page's published URL on exit for redirect

* Preview Open Website: Uses the page's published URL

* Tweaked the published URL logic

* Code amends based on @copilot's suggestions
2025-10-20 11:51:38 +02:00
Kenn JacobsenandGitHub ae2c59b703 Make the indexing batch size configurable (#20543)
* Introduce configurable batch size for indexing

* Stop using Examine indexing events for reporting index rebuild operation completeness (it is volatile)
2025-10-17 15:45:03 +02:00
Andy Butland b142dcc84f Merge branch 'main' into v17/dev 2025-10-17 15:20:55 +02:00
Andy Butland 8b1f18699d Update OpenApi.json and client-side models. 2025-10-17 15:20:01 +02:00
Andy Butland 5a65eb1758 Update OpenApi.json and client-side models. 2025-10-17 15:01:09 +02:00
Andy Butland 5278b67f60 Merge branch 'main' into v17/dev 2025-10-17 14:41:06 +02:00
Anders ReusandGitHub 105cb9da41 Added trashed state so when requesting content from the recycle bin via the management api it will return trashed instead of published state (#20542)
Added trashed state so when requesting content from the recycle bin via the management api, the state will be trashed instead of published.
2025-10-17 14:40:18 +02:00
Andy ButlandandJacob Overgaard a3a8be4717 Templates: Retain layout from file when loading template (closes #20524) (#20529)
Retain layout from file when loading template.
2025-10-17 10:47:21 +02:00
Jacob Overgaard d17ba805b2 build(deps): bumps @umbraco-ui/uui from 1.16.0-rc.0 to 1.16.0 2025-10-17 09:56:42 +02:00
Andy Butland 96f597e440 Merge branch 'release/16.3.1'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-10-17 09:55:20 +02:00
Andy Butland de0503d90c Merge branch 'main' into v17/dev
# Conflicts:
#	src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyValueEditor.cs
2025-10-16 21:12:57 +02:00
Ben WhiteandAndy Butland 6458bb40f9 Don't use non-generic ILogger as a fallback in BlockEditorPropertyValueEditor (#20532)
Update logger service retrieval in BlockEditorPropertyValueEditor
2025-10-16 21:07:16 +02:00
Ben WhiteandGitHub 31bcbc1147 Don't use non-generic ILogger as a fallback in BlockEditorPropertyValueEditor (#20532)
Update logger service retrieval in BlockEditorPropertyValueEditor
2025-10-16 21:06:10 +02:00
Andy Butland 62edad17a1 Bumped version to 16.3.1. 2025-10-16 20:50:59 +02:00
4a504e8c95 Extensions: Adds @provideContext and @consumeContext decorators for a better developer experience (#20510)
* feat: adds first draft of a context consume decorator

* feat: uses an options pattern

* feat: changes approach to use `addInitializer` and `queueMicroTask` instead

* feat: adds extra warning if context is consumed on disconnected controllers

* feat: example implementation of consume decorator

* feat: adds support for 'subscribe'

* feat: initial work on provide decorator

* docs: adds license to consume decorator

* feat: adds support for umbraco controllers with `hostConnected`

* feat: uses asPromise to handle one-time subscription instead

* test: adds unit tests for consume decorator

* feat: adds support for controllers through hostConnected injection

* feat: adds support for controllers through hostConnected injection

* test: adds unit tests for provide decorator

* docs: adds more documentation around usage and adds a few warnings in console when it detects wrong usage

* feat: removes unused controllerMap

* docs: adds wording on standard vs legacy decorators

* docs: clarifies usage around internal state

* feat: adds proper return types for decorators

* docs: adds more types

* feat: makes element optional

* feat: makes element optional

* feat: uses @consume in the log viewer to showcase

* chore: cleans up debug info

* feat: renames to `consumeContext` and `provideContext` to stay inline with our own methods

* chore: removes unneeded typings

* chore: removes not needed check

* chore: removes not needed check

* test: adds test for rendered value

* feat: splits up code into several smaller functions

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* docs: augments code example for creating a context

* Update src/Umbraco.Web.UI.Client/src/packages/log-viewer/workspace/views/search/components/log-viewer-search-input.element.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-16 15:38:26 +01:00
Engiber LozadaandGitHub 271edb5214 News Dashboard: split into card + container, parent handles the data from the repo (#20503)
* Made card element it is own reusable component and passing the data as property.

* Created the umb-news-container element to handle all the priority grouping.

* Added hover styles to normal-priority cards.

* Removed unused variable.
2025-10-16 12:55:43 +00:00
Kenn JacobsenandAndy Butland 369b020d9d Explicitly flush isolated caches by key for content updates (#20519)
* Explicitly flush isolated caches by key for content updates

* Apply suggestions from code review

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-10-16 14:17:04 +02:00
Andreas ZerbstandGitHub ae73fb3431 E2E: Updated acceptance tests to match changes (#20493)
* Updated tests to match changes

* More updates

* Bumped version

* Reverted change
2025-10-16 09:24:56 +00:00
Laura Neto ec354cef92 Merge branch 'release/16.3'
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-10-16 10:05:33 +02:00
Laura Neto a504fd1ef8 Bump version to 16.3.0 2025-10-16 08:22:11 +02:00
Andy Butland c5c417d08e Merge branch 'release/17.0' into v17/dev 2025-10-15 20:13:08 +02:00
Niels Lyngsø cee163ae1f Merge branch 'release/17.0' into v17/dev 2025-10-15 14:13:47 +02:00
Warren BuckleyandGitHub 4c05a114c5 Fixes 20476 - Changes icon to be no entry sign (#20496) 2025-10-15 14:10:39 +02:00
Niels Lyngsø 2412c662df Merge branch 'release/17.0' into v17/dev
# Conflicts:
#	version.json
2025-10-15 10:23:39 +02:00
Andy Butland b25feac011 Merge branch 'main' into v17/dev 2025-10-15 10:12:28 +02:00
Andy ButlandandGitHub e71f36d816 Back Office: Fixes link to workspace root from breadcrumb trail (closes: #20455) (#20459)
Fixes link to workspace root from breadcrumb trail.
2025-10-15 10:06:00 +02:00
Andy Butland a95fd9f340 Merge branch 'main' into v17/dev 2025-10-15 09:48:05 +02:00
Andy ButlandandGitHub fdf759d08d Content Types: Prevent creation of document type with an alias that case insensitively matches an existing alias (closes #20467) (#20471)
Prevent creation of document type with an alias that case insensitively matches an existing alias.
2025-10-15 09:41:41 +02:00
1ab13a970b Dashboard: Add tests for create and using custom dashboard (#20253)
* add tests for custom dashboard

* update test dashboard using helper

* remove extensionRegistry for playwright config

* update helper version for dashboard

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/CustomDashboard.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* fix format code

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2025-10-15 13:33:41 +07:00
e22b459d9c WorkspaceView: Add tests for create and using custom workspace view (#20408)
* WorkspaceView: Add tests for create and using custom workspace view

* update helper version

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/WorkspaceView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/WorkspaceView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* update format code

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/WorkspaceView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/WorkspaceView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

* Update tests/Umbraco.Tests.AcceptanceTest/tests/ExtensionRegistry/WorkspaceView.spec.ts

Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2025-10-15 13:33:24 +07:00
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>iOvergaardleekelleher
a19b9fb5fe UFM: Add camelCase aliases for UFM filters to support UFMJS expressions (closes #20500) (#20501)
* Initial plan

* Add camelCase aliases for UFM filters with hyphens (stripHtml, titleCase, wordLimit)

Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>

* Add manifest tests for camelCase filter aliases

Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>

* discards tests that are not useful

* test: updates imports for stripHtml api

* Exports `UmbUfmStripHtmlFilterApi` class

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: iOvergaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-10-14 16:35:42 +00:00
Andy Butland 07d0d7d2ee Merge branch 'main' into v17/dev 2025-10-14 16:10:59 +02:00
Anders ReusandGitHub cdf9ee4566 Added culture to the ApiContentRouteBuilder to include variant languages. (#20366) (#20499)
Added culture to the ApiContentRouteBuilder to include variant languages.
2025-10-14 16:06:48 +02:00
Mads Rasmussen ac56bffef2 fix import in storybook of moved file 2025-10-14 12:26:25 +02:00
Sven Geusens 068183ac35 Merge branch 'main' into v17/dev 2025-10-14 12:17:06 +02:00
Sven GeusensandGitHub e53220c8f5 Delivery API: Fix not reindexing branch descendants when branch root already published but unchanged (closes #20370) (#20462)
* Fix deliveryApi not reindexing branch descendants when branch root already published and unchanged

* Commit update and name improvement
2025-10-14 12:15:01 +02:00
Andy ButlandandGitHub 12adfd52bd Performance: Reduce number of database calls in save and publish operations (#20485)
* Added request caching to media picker media retrieval, to improve performance in save operations.

* WIP: Update or insert in bulk when updating property data.

* Add tests verifying UpdateBatch.

* Fixed issue with UpdateBatch and SQL Server.

* Removed stopwatch.

* Fix test on SQLite (failing on SQLServer).

* Added temporary test for direct call to NPoco UpdateBatch.

* Fixed test on SQLServer.

* Add integration test verifying the same property data is persisted as before the performance refactor.

* Log expected warning in DocumentUrlService as debug.
2025-10-14 11:22:21 +02:00
Laura Neto 4dbb4eb48b Merge branch 'main' into v17/dev
# Conflicts:
#	Directory.Packages.props
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
2025-10-14 09:48:16 +02:00
Laura NetoandGitHub b5662d9c89 Dependencies: Remove Microsoft.CodeAnalysis.CSharp dependency from Umbraco.Infrastructure (#20481)
* Remove Microsoft.CodeAnalysis.CSharp from Infrastructure project

This was only needed for runtime compilation and thus is no longer needed in Infrastructure.
It also caused dependency problems with EF Core Design in previous versions.

* Disable CPM for UI project to better reflect consumers

This will ensure that we face any potential dependency issues consumers are also likely to run into.

* Add `Microsoft.CodeAnalysis.CSharp` reference to `Umbraco.Cms.DevelopmentMode.Backoffice`
2025-10-14 09:39:53 +02:00
494674d354 Entity Actions: More create button discernible text, extension of #20434 (#20458)
* added hovering and focus border to RTE

* fix main to OG

* fix to main again

* I'm going to cry

* Missing localiztion feature, maybe UmbLitElement?

* added localization controller to fetch localized version

* localization successful for viewActionsFor and CreateFor

* clean up button text

* Changed label for content header to display proper name

* clean up code

* Included button labels for media section

* clean code

* Relocated localization keys,

as `actions_viewActionsFor` already existed.

Also made into a function, to support a fallback label.

* Simplified the "Create for" label/localization

Removed the need for a `getCreateAriaLabel()` method.

* Removed the double-localizations (of `actions_viewActionsFor`)

as the "umb-entity-actions-bundle" component handles this now.

* imports tidy-up

* Simplified localization key condition

* switched to new localization key for other sections for new labeling

* Bumped `@umbraco/playwright-testhelpers` 16.0.55

https://github.com/umbraco/Umbraco.Playwright.Testhelpers/releases/tag/release%2F16.0.55

---------

Co-authored-by: Oskar kruger <obk@umbraco.dk>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-10-14 07:20:01 +00:00
Niels Lyngsø 4c42175ffc Merge branch 'release/17.0' into v17/dev
# Conflicts:
#	version.json
2025-10-14 08:54:54 +02:00
Lee KelleherandGitHub 4ba186633c UFM: Adds $index support to Block editors (fixes #20470) (#20488)
* Block List: adds `$index` support for UFM labels

* Block Grid: adds `$index` support for UFM labels

* Block RTE: adds `$index` support for UFM labels

Which is always zero `0`.
But has been wired up if we do implement the index order in future.
2025-10-14 08:46:48 +02:00
Andy Butland e336f9dfb0 Merge branch 'release/16.3'
# Conflicts:
#	version.json
2025-10-14 08:22:07 +02:00
3393febdca News dashboard: API and rendering of news stories on dashboard (#20416)
* Adding controller

* Lower case route to match other endpoints

* Adding service and typed output

* Renaming to NewsDashboard

* Moving more stuff to service

* Removing unused code

* Some refactoring in accordance with better architecture

* Created repository and mock data source for the news dashboard also display some data in the UI.

* Minor refactoring: naming, aligning with existing controller patterns.

* Update OpenApi.json.

* Update typed client sdk and types.

* Provide language to API endpoint, just in case we want to localize news in the future.

* Obsoleted configuration

* Moved mock data to mocks folder and updated repository to use the actual response model and service from the Api

* Prepared news repository with server data source.

* Rendered news items according to required group structure.
Added TODOs for remaining tasks.

* Fixed FE build issues.

* Update src/Umbraco.Core/Constants-Configuration.cs

* Fixed grid spacing, sanitize code and make the styles closer to the v13.

* Added container query and padding to the card body.

* Fix padding

* Fixed title according to priority.

* Relocated/renamed the news server data-source file

* Simplified the news repo/data-source classes

by extending `UmbControllerBase`, the host constructor is handled for us.

* Added `types.ts` export type files

* Refactored interface name + typing

* Added `uui-loader` component

* Tweaked styles, added box-shadow to cards

Added flexbox gap to the card body.

* Sorted import order

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: engjlr <enl@umbraco.dk>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-10-13 18:20:01 +00:00
Niels Lyngsø 28e4caaad3 fix merge gone wrong 2025-10-13 18:42:06 +02:00
Lee KelleherandGitHub 3ac37f3686 Recycle Bin: Trigger cache invalidation for trashed document/media items (#20483)
* Configure document/media items to listen for `Trashed` server-events for cache invalidation

* Fire reload event on restore destination tree/menu

* Removed "trashed" part of the code comment
2025-10-13 16:32:48 +01:00
0a027dd80d Dependencies: Fixed dependency conflicts when installing Microsoft.EntityFrameworkCore.Design (closes #20421) (#20474)
* Add explicit references to Microsoft.CodeAnalysis.* packages to fix conflicts when installing Microsoft.EntityFrameworkCore.Design

This allows consumers to simply install Microsoft.EntityFrameworkCore.Design without having to manually install specific versions to deal with transitive dependency problems.

* Disable CPM for UI project to better reflect consumers

* Update src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 13:12:45 +02:00
Andy Butland e28153f004 Merge branch 'main' into v17/dev 2025-10-13 06:34:47 +02:00
Bjarne FyrstenborgandGitHub 7b4684cd70 UX: Center align log type in media history view (#20469)
Center align log type in media
2025-10-13 06:34:02 +02:00
Andy Butland 2c284a702a Merge branch 'main' into v17/dev 2025-10-10 15:06:11 +02:00
3df8b9e41a Refactoring: Fixed spelling mistake in method name (#20460)
* Fixed spelling mistake in method name.

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-10 13:00:47 +00:00
Andy Butland 0996891c5c Merge branch 'main' into v17/dev 2025-10-10 10:32:45 +02:00
Bjarne FyrstenborgandGitHub fd34ce5bd7 Icon Picker: Fit icons scroll container to modal height (#20438)
* Fill height and align icons to top

* Auto scrollbar instead

* Auto height of grid rows

* Enforce scroll again
2025-10-10 10:32:19 +02:00
Andy Butland 7a48c11ddd Merge branch 'main' into v17/dev
# Conflicts:
#	src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs
2025-10-10 09:54:19 +02:00
99c2aaf17a Members: Forward port of fix for member lockout issue #16988 from PR #17007 for 16 (#20441)
* Port PR #17007

* Update src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-10 09:52:57 +02:00
leekelleher de449079dd Fixed build error 2025-10-10 08:43:32 +01:00
leekelleher 10bcf5ba72 Merge branch 'main' into v17/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item/tree-item-base/tree-item-element-base.ts
2025-10-10 08:20:55 +01:00
a4c373d3b5 Entity Actions: Create button discernible text (fixes #20205) (#20434)
* added hovering and focus border to RTE

* fix main to OG

* fix to main again

* I'm going to cry

* Missing localiztion feature, maybe UmbLitElement?

* added localization controller to fetch localized version

* localization successful for viewActionsFor and CreateFor

* clean up button text

* Changed label for content header to display proper name

* clean up code

* Included button labels for media section

* clean code

* Relocated localization keys,

as `actions_viewActionsFor` already existed.

Also made into a function, to support a fallback label.

* Simplified the "Create for" label/localization

Removed the need for a `getCreateAriaLabel()` method.

* Removed the double-localizations (of `actions_viewActionsFor`)

as the "umb-entity-actions-bundle" component handles this now.

* imports tidy-up

* Simplified localization key condition

---------

Co-authored-by: Oskar kruger <obk@umbraco.dk>
Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-10-09 13:56:30 +00:00
Andy Butland 5f14365470 Merge branch 'main' into v17/dev
# Conflicts:
#	src/Umbraco.Infrastructure/Mail/EmailSender.cs
2025-10-09 15:41:26 +02:00
bcedc8de2a Emails: Add Expires header (#20285)
* Add `Expiry` header to emails, set default expiry to 30 days and allow user config via `appsettings`

* Remove `IsSmtpExpirationConfigured` as it will always have a value

* Check for `emailExpiration` value

* Removed `EmailExpiration` default value as it should be opt-in

* Simplify SMTP email expiration condition

* Fix APICompat issue

* Add implementation to `NotImplementedEmailSender`

* Rename `emailExpiration` to `expires` to match the SMTP header

* Obsolete interfaces without `expires` parameter, delegate to an existing method.

* Set expiry TimeSpan values from user configurable settings with defaults

* Fix formating

* Handle breaking changes, add obsoletion messages and simplify interfaces.

* Fix default of invite expires timespan (was being parsed as 72 days not 72 hours).

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-10-09 14:27:53 +02:00
767894b723 Color Picker: Validate uniqueness of selected colors (#20431)
* Added unique color checker to color picker.

* Added Unittest for duplicates

* optimized for codescene

* removed the bump and simplified the function

* Fixed behaviour for duplicate checks so unit test passes.
A little refactoring.

* Adds continue so invalid colors aren't checked for duplicates.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-10-09 11:50:11 +02:00
Laura Neto 296858c1ca Merge branch 'main' into v17/dev
# Conflicts:
#	templates/UmbracoProject/.template.config/template.json
2025-10-09 09:51:31 +02:00
1fe7931d07 Migrations: Adjust the JsonBlockValueConverter to handle conflicts with 'values' property (#20429)
* Adjust the `JsonBlockValueConverter` to handle conflicts with 'values' property (due to old data schema)

* Simplify code

* Add unit test to verify change.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-10-09 09:41:41 +02:00
Andy ButlandandGitHub 64836e0b7a Update version from 17.0.0-rc to 17.1.0-rc 2025-10-09 08:54:36 +02:00
Andy ButlandandGitHub 16132b0075 Update Umbraco version for LTS release in template 2025-10-09 06:37:21 +02:00
d6ce8d91a9 PropertyType workspace: layout & labeling adjustments (#20131)
* Property workspace update

* Fixed error with updating the properties

* Unused variable

* Added data-mark to description textarea

* make select 100% width

* tiny appearance-option style adjustments

* Make placeholder property inside the input-with-alias optional

* Moving variations and member type option to their own boxes

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-10-08 18:24:58 +00:00
Andy Butland dab9df3f10 Bumped version to 16.3.0-rc4. 2025-10-08 07:59:10 +02:00
Andy Butland b036eb3a75 Performance: Added request cache to media type retrieval in media picker validation (#20405)
* Added request cache to media type retrieval in media picker validation.

* Applied suggestions from code review.
2025-10-08 07:58:35 +02:00
Nikolaj Geisle 629e905187 Bump version 2025-10-06 21:21:14 +02:00
Andy ButlandandNikolaj Geisle bfd2594c7b Hybrid cache: Check for ContentCacheNode instead of object on exists for hybrid cache to ensure correct deserialization (closes #20352) (#20383)
Checked for ContentCacheNode instead of object on exists for hybrid cache to ensure correct deserialization.

(cherry picked from commit 184c17e2c8)
2025-10-06 21:20:56 +02:00
Andy Butland d9592aa26d Bumped version to 16.3.0-rc2. 2025-10-02 21:16:25 +02:00
Andy ButlandandKenn Jacobsen 97e0c79d94 Caching: Fixes regression of the caching of null representations for missing dictionary items (closes #20336 for 16) (#20349)
* Ports fix to regression of the caching of null representations for missing dictionary items.

* Fixed error raised in code review.

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2025-10-02 21:15:21 +02:00
11074 changed files with 515617 additions and 153324 deletions
+94
View File
@@ -0,0 +1,94 @@
---
name: umb-bump-version
description: Bump the Umbraco CMS version across all required files. Use when the user asks to bump, update, or set the version number — e.g., "bump version to 17.3.4", "set version to 18.0.0-rc", "update version". Accepts the target version as an argument.
argument-hint: <version> (e.g., 17.3.4, 18.0.0-rc)
---
# Bump Version - Umbraco CMS
Updates the Umbraco CMS version string across all files that track it.
**Do NOT use AskUserQuestion if a version argument is provided. Only ask if `$ARGUMENTS` is empty or cannot be parsed as a version.**
## Arguments
- `$ARGUMENTS` - Required: the target version string (e.g., `17.3.4`, `18.0.0-rc`)
## Files to Update
The following 5 files must be updated with the new version:
| # | File | Field |
|---|------|-------|
| 1 | `version.json` | `"version"` |
| 2 | `src/Umbraco.Web.UI.Client/package.json` | `"version"` |
| 3 | `src/Umbraco.Web.UI.Client/package-lock.json` | top-level `"version"` AND `packages[""].version` |
| 4 | `tests/Umbraco.Tests.AcceptanceTest/package.json` | `"version"` |
| 5 | `tests/Umbraco.Tests.AcceptanceTest/package-lock.json` | top-level `"version"` AND `packages[""].version` |
**Note**: For major version bumps (e.g., 17.x to 18.x), `src/Umbraco.Web.UI.Login/package.json` has a caret-ranged dependency on `@umbraco-cms/backoffice` (e.g., `^17.2.0`) that will need manual updating. This skill does not handle that — major bumps involve many other changes beyond version strings.
## Instructions
### 1. Parse and Validate the Version
Extract the version from `$ARGUMENTS`. It must be a valid semver-like string (e.g., `17.3.4`, `18.0.0-rc`, `17.4.0-preview.1`). If no version is provided or it cannot be parsed, ask the user for the target version.
### 2. Read the Current Version
Read `version.json` and extract the current `"version"` value. If the current version already equals the target version, report that the version is already set and stop — do not edit, stage, or commit anything.
Otherwise, display both versions:
```
Bumping version: {current} -> {target}
```
### 3. Update All Files
Update each of the 5 files listed above, replacing the old version with the new version. For each file:
- **`version.json`**: Replace the `"version"` value.
- **`package.json` files**: Replace the `"version"` value (near the top of the file).
- **`package-lock.json` files**: Replace BOTH the top-level `"version"` value AND the `"version"` inside the `"packages": { "": { ... } }` block. These are always in the first ~10 lines of the file.
Use targeted edits — do NOT rewrite entire files. Be precise to avoid changing version strings in dependency entries.
### 4. Verify
After all edits, grep for the target version value across the 5 files to confirm all updates landed correctly:
```bash
grep -n "\"version\": \"{version}\"" version.json src/Umbraco.Web.UI.Client/package.json src/Umbraco.Web.UI.Client/package-lock.json tests/Umbraco.Tests.AcceptanceTest/package.json tests/Umbraco.Tests.AcceptanceTest/package-lock.json
```
Expect exactly 7 matches (one per `package.json` and `version.json`, two per `package-lock.json`).
### 5. Stage and Commit
Stage only the 5 changed files:
```bash
git add version.json src/Umbraco.Web.UI.Client/package.json src/Umbraco.Web.UI.Client/package-lock.json tests/Umbraco.Tests.AcceptanceTest/package.json tests/Umbraco.Tests.AcceptanceTest/package-lock.json
```
Then commit with the message `Bump version to {version}.` — replacing `{version}` with the target version:
```bash
git commit -m "Bump version to {version}."
```
### 6. Report
Output a summary:
```
Version bumped to {version} in:
- version.json
- src/Umbraco.Web.UI.Client/package.json
- src/Umbraco.Web.UI.Client/package-lock.json
- tests/Umbraco.Tests.AcceptanceTest/package.json
- tests/Umbraco.Tests.AcceptanceTest/package-lock.json
Changes staged and committed.
```
+135
View File
@@ -0,0 +1,135 @@
---
name: umb-release-notes
description: Improve a set of auto-generated GitHub release notes for an Umbraco CMS release. Cross-checks the notes against every PR carrying the release label, adds any that are missing, re-files every PR under the most appropriate category, and strips purely-internal entries. Use whenever the user asks to tidy up, improve, complete, or recategorize release notes for a given version, or mentions a release-notes text file plus a version number.
argument-hint: <version> <path-to-generated-notes-file>
---
# Umbraco CMS - Improve Release Notes
Takes a file of auto-generated GitHub release notes and produces an improved version that:
1. **Is complete** — every merged PR carrying the `release/<version>` label appears.
2. **Is well-categorized** — every PR sits under the most appropriate heading.
3. **Is free of noise** — purely-internal entries of no value to a reader are removed.
The result is written to a **new** file alongside the input, so the user can diff the two.
**Run autonomously.** Do NOT use `AskUserQuestion` once the required arguments (version and input file path) are available — only ask if one of them is missing from `$ARGUMENTS` and cannot be inferred (see Arguments). Beyond that, make the categorization calls yourself using the rules below; if a handful are genuinely borderline, place them anyway and note the borderline ones in your closing summary so the user can override.
## Arguments
`$ARGUMENTS` contains two values:
1. **Version** — e.g. `17.5.0`, `18.1.0`. The GitHub label to search is `release/<version>` (so version `17.5.0` → label `release/17.5.0`).
2. **Input file path** — full path to the text file holding the auto-generated notes (e.g. `C:\Temp\release-17.5.0-rc.md`).
If either is missing, ask the user once for the missing value, then proceed.
## Prerequisites
Run `gh auth status`. If it fails, tell the user to authenticate `gh` (e.g. `gh auth login`) and stop — the skill needs the GitHub CLI to query PRs. The repo is always `umbraco/Umbraco-CMS`.
## Procedure
### 1. Read the input notes
Read the input file. Note its structure — it is GitHub's generated format:
- A leading HTML comment (`<!-- Release notes generated ... -->`).
- A `## What's Changed` heading followed by `### <emoji> <Category>` sub-headings, each with `* <title> by @<author> in <url>` bullets.
- A trailing `## New Contributors` section and a `**Full Changelog**: ...` line.
Extract the set of PR numbers already present (parse the `/pull/<number>` from each bullet). Preserve each existing bullet's **exact text** (title, author, URL) when you re-emit it — only its category placement may change.
### 2. Fetch every labelled PR
```bash
gh pr list --repo umbraco/Umbraco-CMS --label "release/<version>" --state closed --limit 1000 \
--json number,title,author,labels,mergedAt \
--jq '.[] | select(.mergedAt != null) | "\(.number)\t\(.author.login)\t\([.labels[].name] | join(", "))\t\(.title)"' | sort -n
```
This is the authoritative list of what the release *should* contain. Each row gives number, author, labels, title.
**Guard against silent truncation.** `gh pr list` caps at `--limit` without warning, so a large release could drop the overflow and the skill would still look "complete". Count the returned rows and compare against the limit:
```bash
gh pr list --repo umbraco/Umbraco-CMS --label "release/<version>" --state closed --limit 1000 --json number --jq 'length'
```
If this equals 1000, the limit was hit — raise `--limit` and re-fetch before continuing. Do **not** proceed on a truncated list.
### 3. Reconcile
- **Missing labelled PRs** (labelled but not in the input file): these must be **added**. Build a bullet as `* <title> by @<author> in https://github.com/umbraco/Umbraco-CMS/pull/<number>`.
- **Author handle.** `<author>` in the template is the raw `.author.login` value — the bullet supplies the leading `@`, so do not prepend another. `gh`'s `.author.login` already returns bot accounts with the `[bot]` suffix as part of the login — Dependabot comes back as `dependabot[bot]`, not `dependabot` or `app/dependabot` (the `app/` form only appears in git committer metadata and CODEOWNERS, never in `gh`'s JSON). So the login is already in the right shape; use it verbatim (e.g. `.author.login` of `dependabot[bot]` renders as `@dependabot[bot]`, matching what GitHub's generator wrote for the existing bullets). The only thing to guard against is accidentally stripping or altering the `[bot]` suffix.
- **PRs in the file but not labelled**: keep them. The generated notes span a commit range (see the `Full Changelog` compare link), so they legitimately include backports / earlier-version PRs that lack the current label. For any of these you need to categorize, fetch its labels with:
```bash
gh pr view <number> --repo umbraco/Umbraco-CMS --json number,title,labels \
--jq '"\(.number)\t\([.labels[].name] | join(", "))\t\(.title)"'
```
Do **not** invent or alter the `New Contributors` section — carry it over verbatim. You cannot reliably recompute first-time contributors, so leave it as the generator produced it (mention this in the summary).
### 4. Categorize every PR
Use exactly these headings, in this order. Omit any heading that ends up with no entries.
| Heading | What goes here | Primary signal |
|---|---|---|
| `### 🙌 Notable Changes` | **Don't recategorize existing entries.** Label-driven — but still add any missing PR carrying this label here. | label `category/notable` |
| `### 💥 Breaking Changes` | **Don't recategorize existing entries.** Label-driven — but still add any missing PR carrying this label here. | label `category/breaking` |
| `### 📦 Dependencies` | Dependency bumps | label `dependencies`; or dependabot author |
| `### 🚀 New Features` | New user- or developer-facing capability | label `type/feature` / `category/feature`; or title introduces/adds a genuinely new capability |
| `### 🚤 Performance` | Performance improvements | label `category/performance`; or `Performance:` title prefix |
| `### 🌈 Accessibility Improvements` | A11y improvements (labels, contrast, keyboard) | label `category/accessibility` / `accessibility`; or clear a11y intent (e.g. "improve contrast", "missing labels") |
| `### 🐛 Bug Fixes` | Fixes to broken/incorrect behaviour | default for anything describing a fix |
| `### 🧪 Testing` | Test additions/changes only | label `category/test-automation` / `area/test`; or `E2E`/`QA`/"acceptance tests"/"unit test coverage"/"add tests" titles |
| `### 🛡️ Code Quality, Documentation and Refactoring` | Refactors, deprecations, API tidy-ups, XML/MD documentation, knowledge-base (`MD`) updates | label `category/refactor`; or titles about refactoring, deprecating, renaming, documenting, constants extraction, MD/CLAUDE.md content |
| `### 🧑‍💻 Developer Experience` | Things that improve the experience of developers building on or contributing to Umbraco — dev tooling, build/watch ergonomics, test mocks/harnesses, backoffice dev utilities | `Developer Experience` title prefix; dev tooling; mock/harness changes |
**Rules:**
- **Notable and Breaking are off-limits for recategorization** — never move a PR that is *already in the input file* into or out of these sections; they are driven purely by their labels and the generator placed them correctly. This does **not** exempt them from completeness: a PR discovered as missing in step 3 that carries `category/notable` or `category/breaking` must still be **added** under the matching section.
- Label signals beat title wording, except a `Performance:`/`Developer Experience:` title prefix is decisive for its section.
- A PR with both `type/feature` and `category/refactor` whose title clearly describes a refactor (e.g. "swap relative imports", "re-export type") belongs under Code Quality, not New Features.
- "Add ... tests"/"unit test coverage" → Testing, even if it also touches docs. If a PR adds XML documentation *and* tests, lead with where the title's emphasis lies (documentation → Code Quality; test coverage → Testing).
- When a PR is genuinely 50/50, pick the more reader-useful heading and list it in your closing summary as borderline.
### 5. Remove purely-internal noise
Drop entries that have **no value to anyone reading release notes** — pure repository plumbing with no shipped impact. Examples:
- Branch/merge maintenance ("Fix main branch after merge issue").
- CI/pipeline fixes that don't change the product.
- Reverts of changes that never shipped in a release.
**Keep** anything that ships in the product or genuinely helps developers building on Umbraco — that includes documentation/MD updates, dev tooling, and test mocks (those go to Code Quality or Developer Experience, they are *not* noise). When unsure whether something is noise, keep it and flag it in the summary rather than silently dropping it. List every removal in your closing summary.
### 6. Write the output
Write to a new file in the **same folder** as the input, named by appending ` - with updates` before the extension:
- Input `C:\Temp\release-17.5.0-rc.md` → Output `C:\Temp\release-17.5.0-rc - with updates.md`
Preserve the leading HTML comment, the `## What's Changed` heading, the `## New Contributors` section, and the `**Full Changelog**` line exactly. Only the `### <category>` groupings and their bullets change.
### 7. Report
Give a concise summary:
- Count of PRs added (with their numbers), and which categories they landed in.
- Notable recategorizations (PRs moved out of the catch-all Bug Fixes into Features/Performance/Testing/etc.).
- Every entry removed, with the one-line reason.
- Any borderline calls the user may want to override.
- The output file path.
## Verification
Before reporting done, confirm:
- Every PR number from step 2 is present in the output (except any you deliberately removed in step 5 — and those must be in the removal list).
- No PR appears under more than one heading.
- Notable and Breaking sections are byte-for-byte unchanged from the input.
- The header comment, New Contributors, and Full Changelog lines are intact.
+251
View File
@@ -0,0 +1,251 @@
---
name: umb-review
description: Automated PR code review for Umbraco CMS. Analyzes changed files for intent, impact on consumers, breaking changes, architecture compliance, and code quality. Non-interactive — outputs a full structured review. Use this skill whenever the user asks to review a branch, review a PR, check their changes for issues, analyze a diff, or validate breaking change patterns — even if they don't say "review" explicitly. Does NOT apply to writing new code, fixing bugs, refactoring, explaining architecture, writing tests, or reviewing documentation content.
argument-hint: <target-branch>
---
# PR Review - Umbraco CMS
Automated, non-interactive PR code review. Analyzes changed files for intent, impact on consumers, breaking changes, architecture compliance, and code quality.
**Do NOT use AskUserQuestion at any point. This skill runs fully autonomously.**
## Arguments
- `$ARGUMENTS` - Optional: target branch to diff against (auto-detected from PR, falls back to `origin/main`)
## Instructions
### 0. Verify GH CLI is Available
Run `gh auth status`. If it fails, read `references/gh-cli-setup.md` and present the setup instructions to the user. Do not proceed with the review.
### 1. Resolve Target Branch
Determine the target branch for comparison using this priority order:
1. **Explicit argument**: If `$ARGUMENTS` is provided and non-empty, use it as the target branch
2. **PR target branch**: If no argument, run `gh pr view --json baseRefName --jq '.baseRefName'` to detect the target branch of the current branch's open PR. If a PR exists, use `origin/{baseRefName}` as the target branch.
3. **Fallback**: If no argument and no PR found (command fails or returns empty), default to `origin/main`
Store the resolved target branch for use in subsequent steps. Log which resolution method was used (e.g., "Target branch: `origin/v18/dev` (from PR #1234)").
### 2. Load Review Standards
#### 2a. Load coding preferences
Read the coding preferences and code review scoring criteria from:
- `references/coding-preferences.md` (relative to this skill file)
Parse and internalize all rules, conventions, scoring categories, and severity definitions. These are your review criteria.
#### 2b. Load area-specific documentation
Once the changed file list is known (after step 3a), determine which areas of the codebase are touched and load the relevant documentation. Execute this sub-step between 3a and 3b. This documentation takes precedence over sibling comparison for architectural and pattern validation.
**Resolution order for each changed file:**
1. **Find the nearest `CLAUDE.md`** — walk up from the changed file's directory toward the repository root. The first `CLAUDE.md` found is the area guide for that file. Read it.
2. **Read referenced docs** — if the `CLAUDE.md` references documentation files (e.g., a `docs/` directory), use the descriptions in the `CLAUDE.md` to determine which docs are relevant to the type of code being changed, and read those. If unsure, read all referenced docs — the cost of reading is low, the cost of missing a convention is high.
3. **Follow cross-references in loaded docs** — if a loaded doc references another doc as covering a complementary or related concern, and the changed files touch that concern, read the referenced doc too. Repeat until no new relevant cross-references remain.
4. **Check for applicable skills** — review the available skills list. If a skill exists for the type of code being changed, read the skill file to understand the expected patterns, structure, and conventions it enforces. Do NOT invoke the skill — just use it as a reference for what the correct implementation should look like.
**Store all loaded documentation** for use in step 4. These docs define the authoritative patterns and conventions that the review evaluates against.
### 3. Gather Changed Files
#### 3a. Collect file list, stats, and diff
Run these git commands (where `{target}` is the resolved target branch):
```bash
git diff {target}...HEAD --name-only --diff-filter=d # changed files (excluding deleted)
git diff {target}...HEAD --stat # line counts per file
git log {target}...HEAD --oneline # commit history
git diff {target}...HEAD # full diff (primary review source)
```
**If no changes found**: Output "No changes found between current branch and `{target}`. Nothing to review." and stop.
#### 3b. Filter out noise files
From the changed file list, classify each file as **noise** or **reviewable**.
**Noise files** (skip entirely — do not read, do not review):
| Pattern | Reason |
| ---------------------------------------------------- | ------------------------------- |
| `*.gen.ts`, `*.gen.cs` | Auto-generated API client code |
| `*.generated.cs`, `*.Designer.cs` (in `Migrations/`) | Auto-generated models/snapshots |
| `*/assets/lang/*.ts` (except `en.ts`) | Non-English translation files |
| `*/mocks/data/*.ts` | Test fixture data |
| `*/dist-cms/*`, `*/storybook-static/*` | Build output |
| `*/TEMP/InMemoryAuto/*` | Runtime-generated models |
| `package-lock.json` | Dependency lock file |
| `appsettings-schema.*.json` | Generated JSON schema |
Log the skip list: "Skipped {N} noise files: {comma-separated list of filenames}"
#### 3c. Read reviewable changed files
Read the full file for every reviewable changed file.
#### 3d. Track file counts
Keep track of these numbers for the review output in step 7: total changed files, noise files skipped, and reviewable files read. Also record: distinct production layers touched, distinct project directories, and total lines changed — these feed step 3e.
#### 3e. Assess PR complexity
Follow the procedure in `references/complexity-assessment.md`. Store the triggered dimensions and suggestions for step 7.
#### 3f. Classify PR scope
Classify the PR to determine which review steps are relevant:
| Classification | Condition | Effect |
| --------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| **Gen-only** | All reviewable files are `gen.ts` | Skip steps 5 and 6; step 4 reviews impact on other code only |
| **Docs-only** | All reviewable files are `.md` | Skip steps 5 and 6; step 4 reviews intent and readability only |
| **Test-only** | All reviewable files are in `tests/` | Skip steps 5 and 6; step 4 reviews intent, code quality, and test coverage only |
| **Config-only** | All reviewable files are `.csproj`, `.props`, `.json` config, or CI/build files | Skip step 5; step 6 checks dependency version changes only |
| **Standard** | Anything else | No skips — run all steps |
### 4. Raw Code Review
Review each changed file holistically. Think like a senior developer reading a colleague's PR. Note all findings without worrying about format or severity yet.
#### 4a. Read and reason about each file
For each changed file, reason about: What does this code do? Is it correct? What's missing — validation, error handling, notifications, cleanup, edge cases? Could this break anything for consumers?
#### 4b. Validate against documentation and patterns
Use a **docs-first** approach: classify the code by what it does, check it against documented conventions, and only fall back to sibling comparison when docs don't cover the pattern.
**Step 1 — Determine the correct approach from documentation, then check whether the PR matches**
A PR is a proposed solution, not the source of truth. This step has two parts that must happen in order — do not start part B until part A is complete.
**Part A — Before validating/judging the implementation**, determine what the correct approach is for each new class or file based on what it does. Use the documentation loaded in step 2b to identify the expected base classes, patterns, and conventions. Write down the expected approach. Classify based on what the code does, not based on what neighboring files look like.
**Part B — Now compare the PR's implementation** against the expected approach from Part A. If it deviates from the documented approach, flag it. If the documentation specifies reference examples, read those examples to verify the implementation matches.
**Pattern match is the leading finding.** If the documentation defines a pattern that fits what the code does, the first and most important finding is whether the code follows that pattern.
**Step 2 — Fall back to sibling comparison**
If the documentation does not cover the specific pattern, or for cross-cutting concerns not addressed in docs, fall back to sibling comparison:
1. **New method on existing class/interface**: Grep for the most similar existing method on the same class using `-A 80` to capture the full method body (e.g., `UpdateCurrentUserAsync` → grep for `UpdateAsync` in the same file with `-A 80`). Compare line by line for missing cross-cutting concerns: notifications/events, validation, scoping, authorization, error handling, audit logging.
2. **New TS class**: Grep for siblings by base class (`extends {BaseClass}`) or by interface (`implements {Interface}`) or by name suffix (e.g., `CurrentUserController` → grep for `UserController`). Compare for missing concerns.
3. **New CS class**: Grep for siblings by base class (`class {ClassName} : {BaseClass}`) or by interface (`class {ClassName} : {Interface}`) or by name suffix (e.g., `ManagementApiComposer` → grep for `ApiComposer`). Compare for missing concerns.
**Important:** Sibling comparison validates cross-cutting concerns, but it must not override documented conventions. If a sibling deviates from documented patterns, that sibling is wrong — do not copy its deviation.
Store your raw findings — they feed into step 7.
### 5. Impact Analysis
**Skip this step if PR scope is docs-only, test-only, or config-only.**
Follow the procedure in `references/impact-analysis.md`.
### 6. Breaking Changes Check
**Skip this step if PR scope is docs-only or test-only. If config-only, only check for dependency version changes that could break consumers.**
Follow the procedure in `references/breaking-changes.md`.
### 7. Consolidate and Output Review
Merge findings from step 4 (raw review), step 5 (impact analysis), and step 6 (breaking changes). For each finding, assign severity (Critical/Important/Suggestion) and verify it relates to changed code — not pre-existing issues. Before outputting, drop any finding about whitespace, blank lines, formatting, or comment wording. Then present the review in this exact format:
```markdown
## PR Review
**Target:** `{target_branch}` · **Based on commit:** `{head_sha}`
[If any skipped files, append: · **Skipped:** {skipped} files out of {total} total]
[If step 3f classification is not "Standard", append: · **Classified as:** {classification}]
[12 sentences: what this PR accomplishes , keep it as short as possible, only highlight the primary essence.]
- **Modified public API:** {changed existing interfaces/types/classes/methods}
[Omit bullet if none]
- **Affected implementations (outside this PR):** {interfaces/types/classes/methods using modified public API}
[Omit bullet if none]
- **Breaking changes:** {violations with specifics}
[Omit bullet if none]
- **Other changes:** {changes not listed above that an Umbraco user, plugin developer, or API consumer would notice — e.g., behavior changes, default value changes, error message changes, new configuration options, removed functionality. Exclude internal renames, formatting, and private implementation details.}
[Omit bullet if none]
[If step 3e triggered any dimensions, insert this block. Omit entirely if nothing triggered:]
> [!NOTE]
> **Complexity advisory** — This PR may benefit from splitting.
>
> - **{Dimension}:** {Explanation and concrete split suggestion from step 3e}
> [one bullet per triggered dimension]
>
> _This is an observation, not a blocker. The full review follows below._
---
### Critical
[Must fix before merge — security vulnerabilities, data loss, broken functionality, breaking changes without proper patterns]
- **`{file}:{line}`**: {problem} → {fix}
[Omit section if none]
### Important
[Should fix — performance issues, missing tests, architectural violations, pattern misuse]
- **`{file}:{line}`**: {observation} → {suggestion}
[Omit section if none]
### Suggestions
[Nice to have — readability, minor refactoring, alternative approaches]
- **`{file}:{line}`**: {detail}
[Omit section if none]
---
[One of:]
## Approved
This looks good to be merged as-is, but please do a manual sanity check and testing before merging.
## Approved with Suggestions for improvement
Good to go, but please carefully consider the importance of the suggestions.
## Request Changes
Critical and important issues must be addressed first.
## Needs re-work
This is in such a bad state that the feedback of this review is not sufficient to guide improvements, the PR cannot be approved.
```
**Guidelines for the review output:**
— When reporting information, be extremely concise and sacrifice grammar for sake of concision.
- Only review code that was changed in the diff — pre-existing issues are out of scope. Focus on what compilers and linters cannot catch: behavioral side-effects (e.g., a changed default alters runtime behavior for consumers), architectural violations (e.g., a new dependency breaks layering), breaking changes for external consumers of the public API, and security implications. Leave type errors, missing imports, and broken references to CI.
- Be specific — always reference file and line number
- Explain WHY something is an issue, not just WHAT, but avoid stating the obvious.
- For complex matters, provide concrete fix suggestions, including code snippets when helpful
- Keep it constructive — the goal is to help, not gatekeep
- Don't repeat the same finding for every occurrence — mention it once and note "same pattern in {other files}"
- Focus on substantive issues only. Do NOT flag purely cosmetic or stylistic concerns. Specifically, never flag: code formatting or whitespace, comment grammar or wording, redundant-but-harmless syntax (e.g., optional chaining after a truthiness check), code duplication that doesn't cause bugs, or HTML template cosmetics. The only exception is when a stylistic issue has a concrete impact on performance or rendering. Note: missing JSDoc/documentation on public or exported APIs is a substantive finding (per coding preferences), not a cosmetic one — flag it as a Suggestion.
- For breaking changes, reference the specific pattern from the CLAUDE.md that should be applied
- Do not suggest changes that would themselves introduce breaking changes. If a suggestion would alter public API surface (e.g., changing return types, renaming public members), it is not appropriate for a PR targeting `main` within a major version. Only suggest non-breaking alternatives.
@@ -0,0 +1,97 @@
{
"skill_name": "umb-review",
"evals": [
{
"id": 0,
"name": "pr-22214-large-frontend-refactor",
"prompt": "Review the changes in PR #22214 (branch origin/pr/22214 targeting main). This is a large frontend refactor migrating create entity actions to use entityCreateOptionAction extensions, with deprecations.",
"expected_output": "A structured review that identifies frontend deprecation patterns, flags the large PR complexity, handles 75+ files correctly, checks for breaking changes in exported components, and produces the correct output format.",
"pr_number": 22214,
"pr_branch": "origin/pr/22214",
"base_branch": "origin/main",
"files": [],
"assertions": [
{"id": "deprecation-patterns-noted", "text": "Review identifies deprecation patterns (@deprecated, UmbDeprecation)"},
{"id": "frontend-breaking-change-awareness", "text": "Checks frontend-specific breaking changes (exports, custom elements) not just backend"},
{"id": "file-references-present", "text": "Findings reference specific files with line numbers"},
{"id": "no-false-critical-on-deprecations", "text": "Properly deprecated code is NOT flagged as Critical breaking change"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues (formatting, whitespace, naming conventions, comment grammar, code style preferences) unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."},
{"id": "manifest-alias-rename-detected", "text": "Alias renames (CreateOptions → Create) flagged as Critical breaking change"},
{"id": "non-exported-deletions-dismissed", "text": "Deleted action classes NOT flagged as breaking (verified against package.json exports)"},
{"id": "noise-files-filtered", "text": "Does not review noise files (generated files, lock files, etc.)"},
{"id": "complexity-advisory-triggers", "text": "Review includes a complexity/split advisory for the large 75+ file scope"}
]
},
{
"id": 1,
"name": "pr-21672-small-frontend-bugfix",
"prompt": "Review the changes in PR #21672 (branch origin/pr/21672 targeting main). This is a small 4-file frontend bugfix implementing tab validation badges in the block editor.",
"expected_output": "A clean review that correctly identifies this as a small focused bugfix, avoids false positives, and either approves or approves with minor suggestions.",
"pr_number": 21672,
"pr_branch": "origin/pr/21672",
"base_branch": "origin/main",
"files": [],
"assertions": [
{"id": "complexity-advisory-absent", "text": "Review does NOT include a complexity/split advisory"},
{"id": "no-false-breaking-changes", "text": "Review does not flag breaking changes"},
{"id": "proportionate-verdict", "text": "Verdict is 'Request Changes'"},
{"id": "concise-review", "text": "Review output is under 200 lines"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues (formatting, whitespace, naming conventions, comment grammar, code style preferences) unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."}
]
},
{
"id": 2,
"name": "pr-22217-small-backend-webhook",
"prompt": "Review the changes in PR #22217 (branch origin/pr/22217 targeting v18/dev). This is a tiny 3-file backend change to the default webhook payload type.",
"expected_output": "A concise review that correctly resolves v18/dev as target branch, handles the small change proportionately, and considers the behavioral impact of changing a default value.",
"pr_number": 22217,
"pr_branch": "origin/pr/22217",
"base_branch": "origin/v18/dev",
"files": [],
"assertions": [
{"id": "correct-target-branch", "text": "Review references 'v18/dev' as the target branch (not 'main')"},
{"id": "default-value-change-noted", "text": "Review discusses the behavioral impact of changing the default payload type"},
{"id": "proportionate-review", "text": "Review output is under 150 lines"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues (formatting, whitespace, naming conventions, comment grammar, code style preferences) unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."},
{"id": "ignores-preexisting-issues", "text": "Does NOT flag the ~30 builder extension methods with Legacy defaults (pre-existing, not changed in the PR)"},
{"id": "side-effect-detection", "text": "Flags stale WebhookSettings.cs docs as a side-effect of the constant value change"},
{"id": "consumer-identification", "text": "Identifies affected consumers outside the PR (WebhookSettings, UmbracoBuilder, or WebhookEventCollectionBuilderExtensions)"}
]
},
{
"id": 3,
"name": "pr-22268-frontend-feature-workspace-modal",
"prompt": "Review the changes in PR #22268 (branch origin/pr/22268 targeting main). This is a 29-file frontend feature adding a current user workspace modal.",
"expected_output": "A review of a medium-sized new feature PR. Should assess the new code for architectural compliance, check for breaking changes (new exports, custom elements), and evaluate code quality without flagging pre-existing issues.",
"pr_number": 22268,
"pr_branch": "origin/pr/22268",
"base_branch": "origin/main",
"files": [],
"assertions": [
{"id": "complexity-advisory-triggers", "text": "Review includes a complexity/split advisory (3 layers: Core, API, Frontend across 27+ files)"},
{"id": "breaking-changes-on-interface-additions", "text": "Flags new interface methods without default implementations as breaking changes (Pattern 3)"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."},
{"id": "diff-scoped", "text": "All findings reference code that was changed in the diff, not pre-existing issues"},
{"id": "new-feature-assessed", "text": "Review assesses the new feature's architecture, patterns, or integration approach — not just absence of bugs"},
{"id": "no-false-notification-finding", "text": "Review does NOT flag UpdateCurrentUserAsync as missing UserSavingNotification/UserSavedNotification — the sibling UpdateAsync also does not publish these notifications, so flagging their absence would be a false positive"}
]
},
{
"id": 4,
"name": "pr-22215-frontend-architecture-violation",
"prompt": "Review the changes in PR #22215 (branch origin/pr/22215 targeting main). This is a 2-file frontend feature adding user management to the user group workspace.",
"expected_output": "A review that catches the architecture violation: the workspace context directly imports and calls UserService and UserGroupService (generated API clients) instead of going through a repository. In the Umbraco backoffice, workspace contexts access data via repositories, not by calling API services directly. The review should flag this as a significant architecture issue and request changes.",
"pr_number": 22215,
"pr_branch": "origin/pr/22215",
"base_branch": "origin/main",
"files": [],
"assertions": [
{"id": "service-bypass-detected", "text": "Review flags that the workspace context directly imports/calls UserService or UserGroupService instead of using a repository"},
{"id": "repository-pattern-recommended", "text": "Review recommends using the repository pattern (going through a repository/data-source layer) rather than calling API services directly from the workspace context"},
{"id": "verdict-request-changes", "text": "Verdict is 'Request Changes' (the architecture violation warrants requesting changes, not just approving with suggestions)"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues (formatting, whitespace, naming conventions, comment grammar, code style preferences) unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."},
{"id": "no-false-breaking-changes", "text": "Review does not flag breaking changes (this PR only adds new code, no public API is removed or modified)"}
]
}
]
}
@@ -0,0 +1,249 @@
# Breaking Changes Reference
This document describes how to detect and validate breaking changes during PR review. It covers both backend (.NET) and frontend (TypeScript/Lit) patterns.
---
## Version Detection
**Always read `version.json`** at the repository root to determine the current major version. This drives the obsolete removal target calculation:
- Current major version: read from `version.json``version` field (e.g., `"17.4.0-rc"` → major version `17`)
- Obsolete removal target: `current + 2` (e.g., if current is 17, removal is scheduled for Umbraco 19)
- Format: `[Obsolete("... Scheduled for removal in Umbraco {current+2}.")]`
---
## Backend (.NET) Breaking Changes
### What Constitutes a Breaking Change
Any of these on a `public` or `protected` member:
- Removing or renaming a class, interface, struct, record, or enum
- Removing or renaming a method, property, or field
- Changing a method signature (parameters, return type)
- Adding required parameters to an existing method
- Adding methods to a public interface (without default implementation)
- Changing a constructor signature on a public class
- Removing or changing enum values
- Changing type hierarchy (base class, implemented interfaces)
### Pattern 1: Obsolete Constructor + StaticServiceProvider
When a public class needs new dependencies, the existing constructor must be preserved.
**Correct pattern:**
```csharp
[Obsolete("Please use the constructor with all parameters. Scheduled for removal in Umbraco 19.")]
public MyService(IDependencyA depA)
: this(
depA,
StaticServiceProvider.Instance.GetRequiredService<IDependencyB>())
{
}
public MyService(IDependencyA depA, IDependencyB depB)
{
_depA = depA;
_depB = depB;
}
```
**Validation checklist:**
- [ ] Old constructor has `[Obsolete]` attribute with correct removal version
- [ ] Old constructor calls new constructor via `: this(...)`
- [ ] `StaticServiceProvider.Instance.GetRequiredService<T>()` used for new params only
- [ ] DI registration uses the NEW constructor (old is for external consumers only)
- [ ] Removal version is `{current_major + 2}`
**Common mistakes to flag:**
- Removing the old constructor entirely (breaking change!)
- Old constructor NOT calling new constructor (code duplication)
- Wrong removal version in `[Obsolete]`
- Missing `StaticServiceProvider` resolution for new dependencies
- DI registration still using the old constructor
### Pattern 2: Obsolete Method + New Overload
When a method signature needs to change, add the new overload and obsolete the old.
**Correct pattern:**
```csharp
[Obsolete("Use the overload taking all parameters. Scheduled for removal in Umbraco 19.")]
public void DoThing(string name)
=> DoThing(name, extraParam: null);
public void DoThing(string name, string? extraParam)
{
// Real implementation here
}
```
**Validation checklist:**
- [ ] Old method has `[Obsolete]` attribute with correct removal version
- [ ] Old method calls new method, providing defaults for new parameters
- [ ] All internal callers updated to use the new method
- [ ] No internal code references the obsolete method (except the delegation)
### Pattern 3: Default Interface Implementation
When adding methods to a public interface, provide a default implementation.
**Correct pattern:**
```csharp
public interface IMyService
{
void ExistingMethod();
// New method with default implementation
void NewMethod(string param)
=> ExistingMethod(); // delegate to existing if possible
}
```
**Strategies for defaults (in order of preference):**
1. Use existing interface methods to satisfy the contract
2. Return a sensible default (empty collection, null, etc.)
3. Throw `NotImplementedException` if no reasonable default exists
**Validation checklist:**
- [ ] New interface method has a default implementation
- [ ] TODO comment present: `// TODO (V{next-major}): Remove the default implementation when {obsolete method} is removed.`
- [ ] Default implementation is functionally correct (even if not optimal)
- [ ] If `StaticServiceProvider` is used in default impl, noted as temporary
### Obsolete Attribute Validation
For any `[Obsolete]` attribute found in changed code:
1. **Format**: Must contain `"Scheduled for removal in Umbraco {version}."`
2. **Version**: Must be `current_major + 2` (read from `version.json`)
3. **Pragma**: Where obsolete members must call each other, `#pragma warning disable CS0618` / `#pragma warning restore CS0618` must be present
### Internal Caller Check
After finding obsolete patterns, verify:
- Search the codebase for usages of the obsolete member
- **No internal code** (inside `src/`) should reference obsolete members
- Only the obsolete member's own delegation (calling the new version) is acceptable
- External consumers (outside the repo) get the deprecation period to migrate
---
## Frontend (TypeScript/Lit) Breaking Changes
The backoffice is published as `@umbraco-cms/backoffice` with 140+ named exports. Plugin developers depend on this public API surface.
**Critical frontend rule (does not apply to backend .NET where `public`/`protected` visibility determines the API surface): only symbols reachable through the `package.json` `exports` field are public API.** Anything not exported — whether classes, functions, constants, types, or entire files — is an internal implementation detail, even if other internal code imports it. Removing or changing unexported frontend symbols is not a breaking change. Before flagging a frontend deletion or rename as breaking, verify the symbol is reachable via `package.json` exports. If it is not, do not flag it.
### Custom Elements (Web Components)
**Breaking changes:**
- Renaming or removing a registered custom element tag (`umb-*`)
- Removing elements from `HTMLElementTagNameMap`
- Removing or changing `@property()` decorated fields on exported components
- Removing event emissions (checked via `this.dispatchEvent`)
- Removing CSS custom properties (`@cssprop` in JSDoc)
- Removing CSS parts (`@csspart` in JSDoc)
**How to detect:**
- Check diff for removed `@customElement('umb-...')` decorators
- Check diff for removed `@property()` fields on exported components
- Check diff for removed entries in `HTMLElementTagNameMap` declarations
### Exported Types/Interfaces
**Breaking changes:**
- Removing exports from `package.json` `exports` field
- Changing the shape of exported interfaces (removing properties, changing types)
- Renaming exported types (consumers import by name)
- Removing union type members
- Changing generic type parameter constraints
**How to detect:**
- Check if `package.json` `exports` field is modified
- Check diff for removed `export` statements
- Check diff for changed interface/type shapes
### Manifest/Extension System
**Breaking changes:**
- Renaming a manifest `alias` value — plugin developers reference aliases by string in conditions, overwrites, and extension registry lookups. Alias renames are not caught by the compiler since they are string-based. A renamed alias silently breaks any plugin that references the old string.
- Removing support for a manifest `type` that plugins use
- Changing manifest `alias` resolution or validation
- Removing or renaming manifest `kind` types
- Changing extension bundle structure
**How to detect:**
- **Alias renames**: Compare `alias:` values in manifest files before and after. Changed alias strings are Critical — the old alias should be preserved as a deprecated entry.
- Search for changes to manifest type definitions
- Check for removed or renamed manifest kinds
### Context API
**Breaking changes:**
- Removing context tokens from exports
- Changing the shape of data provided by a context
- Removing context provider/consumer mechanisms
**How to detect:**
- Check for removed context token exports
- Check for changes to context provider classes
### Controllers/Lifecycle
**Breaking changes:**
- Changing controller base class inheritance requirements
- Removing controller lifecycle hooks
- Breaking cleanup mechanisms in `disconnectedCallback()`
### Observable/State
**Breaking changes:**
- Removing observable properties from the public API
- Changing observable emission patterns
### npm Publishing
**Breaking changes:**
- Changing version constraints that exclude previously-supported versions
- Adding incompatible peer dependency constraints
**How to detect:**
- Check if `package.json` `peerDependencies` or `dependencies` changed
- Verify version ranges are not narrowed
---
## Reporting Breaking Changes
When a breaking change is detected, report:
1. **What**: The specific change and which public symbol is affected
2. **Pattern**: Which mitigation pattern should be applied (Pattern 1, 2, or 3 for backend)
3. **Severity**: Critical (no mitigation present) or Important (mitigation present but incorrect)
4. **Fix**: Concrete code suggestion showing the correct pattern
If no breaking changes are detected, state: "No breaking changes detected."
@@ -0,0 +1,168 @@
# Coding Preferences & Review Criteria
These are the coding preferences and code review standards used by the review skill. They define what the review evaluates against.
---
## Testing
- **Always create blackbox tests** for new/changed code
- Choose the appropriate test level:
- **Unit tests** for isolated logic
- **Integration tests** for application services/use cases
- **E2E tests** for API endpoints
### Test Class Naming
- Test classes must be postfixed with `Tests` (e.g., `OrderServiceTests`)
- One test class per class under test
### Test Method Naming
**C# tests**: Use the `Can_`/`Cannot_` pattern with PascalCase underscore-separated words:
- `Can_Schedule_Publish_Invariant`
- `Cannot_Delete_Non_Existing`
- `Can_Schedule_Publish_Single_Culture`
Large test classes are split into partial files by method: `ContentServiceTests.Delete.cs`, `ContentServiceTests.Publish.cs`.
**TypeScript tests**: Use BDD-style `it()` with natural language descriptions:
- `it('should not allow the returned value to be lower than min')`
- `it('converts string to camelCase')`
### Unit Tests
- Optional, but must be blackbox tests so refactoring does not break tests
### Integration Tests
- Every use case / application service must have integration tests
- Tests run against real database (containerized or similar)
- Test the full flow from application layer through infrastructure
### E2E Tests
- Every API endpoint must have E2E tests
- Test realistic scenarios including error cases
---
## Trade-offs
When making decisions, prioritize:
- **Readability** over cleverness
- **Flexibility** over rigidity
- Explain trade-offs when deviating from these defaults
---
## Breaking Changes
- Communicate breaking changes at the **OpenAPI/openapi.json level**
- Clearly document what changed and the migration path
---
## Documentation
- **Document all public or exported types** (classes, interfaces, types, methods, properties)
- Keep documentation in sync with code changes
- Add **JS Docs** on all public frontend APIs (classes, methods, properties)
- Focus on "why" and usage, not restating the obvious
---
## Dependencies
- Use what's available in the codebase, unless there is no good choice
- **Flag new dependencies** for review — new packages should be justified
- Prefer well-maintained, widely-used packages
---
## Error Messages & Logging
- **User-facing errors**: Clear, friendly, actionable
- **Log messages**: Technical, detailed, with context
- Include correlation IDs and relevant data in logs
---
## Security
- **Always check for security issues** using OWASP Top 10 as baseline
- Flag potential vulnerabilities immediately
- Suggest secure alternatives when spotting risky patterns
- Apply principle of least privilege
---
## Immutability
- Prefer **immutability** by default
- Allow internal properties to be mutated, as long as they are not direct references coming from the outside
---
## Nullability
- **TypeScript / JavaScript**
- Prefer `undefined` for optional/omitted values (e.g., optional parameters, props, and fields)
- Use `null` only when the domain model explicitly encodes "no value" or "not set" (e.g., `string | null` from APIs/DB), and be consistent with existing types
- Avoid mixing `null` and `undefined` for the same concept within the same model or API surface
- **C#**
- use nullable types (e.g., `string?`, `int?`) where absence is valid
- Prefer domain modeling (value objects, options/results, empty collections) over `null` where appropriate, but respect existing conventions in the codebase
---
## C# Specific
- use Notification pattern (not C# events), Composer pattern (DI registration), Scoping with `Complete()`, Attempt pattern for operation results.
---
## Architecture
- Follow **Clean Architecture** principles
- **Fail-fast** principle: detect and report errors as early as possible
- Within the established layered architecture (Core/Infrastructure/Web/API), organize code by feature inside each layer where practical, while preserving dependency direction
- One class per file
- Avoid N+1 queries
- Profile before optimizing non-critical paths
### Type Hierarchy Consistency
When parallel model types have inconsistent relationships to a shared base type:
**TypeScript**: manipulations via `Omit`, `Pick`, intersection overrides, or workarounds like `as unknown as` / double-casts to bridge type mismatches.
**C#**: hiding base members with `new` to change types, explicit interface implementations to mask mismatches, or downcasting base return types in derived classes.
- **Do NOT suggest** the PR code should deviate from its base type to match a sibling that already deviates. Copying the deviation spreads the problem.
- **Do flag** the architectural inconsistency: parallel models should share a compatible base contract. The model that manipulates or deviates from the base type is the one that needs attention — not the one that extends it correctly.
- **Frame the suggestion** as: "These related models have inconsistent type hierarchies. `{deviating type}` manipulates the base contract of `{base type}`, which forces shared consumers like `{shared utility}` to require a shape that conforming subtypes can't satisfy."
---
## Code Style
- Follow standard naming conventions for the language (C# or JS/TS)
- Keep components small and focused on a single responsibility
- Prefer early returns
- Small functions
- No nested ternaries
---
## Severity Levels
| Severity | Meaning |
|----------|---------|
| **Critical** | Must fix before merge — security vulnerabilities, data loss risks, broken functionality |
| **Important** | Should fix — performance issues, missing tests, architectural violations |
| **Suggestion** | Nice to have — readability, minor refactoring, alternative approaches |
@@ -0,0 +1,33 @@
# PR Complexity Assessment
Evaluate whether the PR's scope suggests it should be split. This assessment is **informational only** — it never blocks or shortens the review.
## Always check: Formatting mixed with logic
This check applies to every PR regardless of size or scope.
Run both commands and compare per-file line counts:
```bash
git diff {target}...HEAD --stat
git diff {target}...HEAD --stat --ignore-all-space
```
For any file where the whitespace-ignored diff is less than **half** the full diff size (and the full diff is over 50 lines), that file has significant formatting changes mixed with logic. Flag it with a split suggestion: "File(s) {list} contain significant formatting changes mixed with logic. Consider a separate formatting-only commit or PR to keep the functional diff reviewable."
## Multi-project scope check
Skip this section entirely if ALL production files reside in a single project directory or if the PR is docs-only, test-only, dependency-bump-only, or rename-only.
Otherwise, flag any dimension that applies:
| Dimension | Condition | Suggestion |
|---|---|---|
| **Size** | 30+ files OR 1500+ lines, spanning 2+ projects | "If changes in {projectA} and {projectB} are independently functional, they could be separate PRs." |
| **Layer spread** | 3+ layers touched (Core/Infrastructure/Web/API/Frontend), 10+ files | "Consider splitting by layer — e.g., Core+Infrastructure first, then API/Frontend consumers." |
| **Mixed intent** | 2+ intent categories (new feature, bugfix, refactor, dependency update) with 15+ files or 3+ projects | "Consider extracting the {secondary intent} into a separate PR." |
Intent categories — detect from diff characteristics, not commit messages:
- **New feature**: new files or new `public`/`export` declarations
- **Bug fix**: small targeted edits, no new files (don't co-flag with new feature)
- **Refactor**: file renames, symbols moved but logic unchanged
- **Dependency update**: changes to `.csproj`, `Directory.Packages.props`, `package.json`
@@ -0,0 +1,23 @@
# GH CLI Setup Instructions
The GitHub CLI (`gh`) is required for this review skill to detect PR target branches.
## Installation
Install via Homebrew:
```
brew install gh
```
Or see https://cli.github.com/ for other installation methods.
## Authentication
After installing, authorize by running this in the terminal (use the `!` prefix in Claude Code):
```
! gh auth login
```
Follow the prompts to authenticate with your GitHub account.
@@ -0,0 +1,153 @@
# Impact Analysis Reference
This document describes how to perform impact analysis during PR review. The goal is to look beyond the diff to understand how changes affect consumers in other parts of the codebase.
---
## 1. Extract Changed Public Symbols
Scan the diff output for changes to public API surface:
### Backend (.NET)
Look for added, modified, or removed lines containing:
- `public class`, `public abstract class`, `public sealed class`
- `public interface`
- `public record`, `public struct`, `public enum`
- `public` or `protected` methods, properties, fields
- `public static` members
- Constructor signatures on public types
### Frontend (TypeScript/Lit)
Look for changes to:
- `export class`, `export interface`, `export type`, `export enum`
- `export function`, `export const`
- `@property()` decorated fields on exported components
- `@customElement()` registrations
- Entries in `package.json` `exports` field
Collect a list of all changed public symbol names (type names, method names, property names).
---
## 2. Search for Consumers
For each changed public symbol, search the `src/` directory for usages **outside the changed file itself**.
### Grep Strategy
Use the Grep tool with these settings:
```
pattern: {symbol name}
path: src/
output_mode: files_with_matches
head_limit: 20
```
Use `head_limit: 20` to avoid overwhelming results — if there are more than 20 consumers, note "20+ consumers found" and list the first 20.
### What to Search For
For each changed type/method, search for:
- **Type references**: class name, interface name (e.g., `IContentService`)
- **Method calls**: method name in context (e.g., `\.GetById\(` for a method rename)
- **Constructor usage**: `new TypeName(`
- **DI registrations**: `.AddSingleton<IType, Type>`, `.AddScoped<`, `.AddTransient<`
- **Notification handlers**: if a notification type changed, search for `INotificationHandler<NotificationTypeName>` and `INotificationAsyncHandler<NotificationTypeName>`
- **Interface implementations**: if an interface changed, search for `: IInterfaceName` or `IInterfaceName,`
### Excluding the Changed File
When reporting consumers, exclude files that are part of the PR's changes (they're already being reviewed). The interesting consumers are those **outside** the PR that may be affected.
---
## 3. Check Dependency Flow Direction
The Umbraco architecture enforces strict unidirectional dependencies:
```
Api.Management / Api.Delivery (depend on Api.Common)
Api.Common (depends on Web.Common)
Web.Common (depends on Infrastructure)
Infrastructure (depends on Core)
Core (no dependencies)
```
### Layer Mapping
Map each changed file to its architectural layer:
| Path prefix | Layer |
|---|---|
| `src/Umbraco.Core/` | Core |
| `src/Umbraco.Infrastructure/` | Infrastructure |
| `src/Umbraco.PublishedCache.*` | Infrastructure |
| `src/Umbraco.Examine.Lucene/` | Infrastructure |
| `src/Umbraco.Cms.Persistence.*` | Infrastructure |
| `src/Umbraco.Web.Common/` | Web |
| `src/Umbraco.Web.UI/` | Web (Application) |
| `src/Umbraco.Web.Website/` | Web |
| `src/Umbraco.Cms.Api.Common/` | API |
| `src/Umbraco.Cms.Api.Management/` | API |
| `src/Umbraco.Cms.Api.Delivery/` | API |
| `src/Umbraco.Web.UI.Client/` | Frontend |
| `tests/` | Test |
### Violation Detection
Flag if a change introduces:
- **Core depending on Infrastructure**: Core file importing/referencing Infrastructure types
- **Core depending on Web/API**: Core file importing/referencing Web or API types
- **Infrastructure depending on Web/API**: Infrastructure file importing Web or API types
- **Cross-API dependencies**: Management API depending on Delivery API or vice versa
### How to Check
1. For each changed file, identify its layer
2. Read the file's `using` statements (C#) or `import` statements (TS)
3. Check if any imports reference a higher layer
4. Also check if new parameters or return types come from higher layers
---
## 4. Flag Cross-Project Risks
### High-Risk Patterns
These changes have high ripple potential:
- **Interface changes in Core** — all implementations in Infrastructure must be updated
- **Notification type changes** — all handlers across the codebase are affected
- **Base class changes** — all derived classes are affected
- **Composer changes** — can affect DI container and runtime behavior globally
- **Shared model/DTO changes** — can affect serialization, API contracts, and consumers
### What to Report
For each cross-project risk found, report:
1. **What changed**: The specific symbol and how it changed
2. **Who is affected**: List of consuming files/projects found via Grep
3. **Risk level**: Whether the consumers will break (compile error), behave differently (runtime), or are unaffected
4. **Recommendation**: Whether the PR should include updates to affected consumers
---
## 5. Performance Notes
- Use `head_limit: 20` on all Grep searches to cap results
- Only search for symbols that actually changed (not every symbol in the file)
- For very common type names (e.g., `IScope`, `ILogger`), consider adding more context to the search pattern to reduce false positives
- Skip impact analysis for test files — they don't have external consumers
- Skip impact analysis for private/internal members — they can't have external consumers
+5 -13
View File
@@ -70,18 +70,6 @@ trim_trailing_whitespace = true
[*.less]
trim_trailing_whitespace = false
##########################################
# File Header (Uncomment to support file headers)
# https://docs.microsoft.com/visualstudio/ide/reference/add-file-header
##########################################
# [*.{cs,csx,cake,vb,vbx}]
file_header_template = Copyright (c) Umbraco.\nSee LICENSE for more details.
# SA1636: File header copyright text should match
# Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project.
# dotnet_diagnostic.SA1636.severity = none
##########################################
# .NET Language Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions
@@ -102,7 +90,7 @@ dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Modifier preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers
dotnet_style_require_accessibility_modifiers = always:warning
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning
dotnet_style_readonly_field = true:warning
@@ -136,6 +124,10 @@ dotnet_code_quality_unused_parameters = all:warning
dotnet_style_operator_placement_when_wrapping = end_of_line
# https://github.com/dotnet/roslyn/pull/40070
dotnet_style_prefer_simplified_interpolation = true:warning
# File header preferences
file_header_template = Copyright (c) Umbraco.\nSee LICENSE for more details.
dotnet_diagnostic.SA1633.severity = none # Suppressed until we decide to enforce it
dotnet_diagnostic.SA1636.severity = none # Suppressed since we are using StyleCop
# C# Code Style Settings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings
+5
View File
@@ -0,0 +1,5 @@
UMBRACO_CLIENT_ID=umbraco-back-office-mcp
UMBRACO_CLIENT_SECRET=1234567890
UMBRACO_BASE_URL=https://localhost:44339
NODE_TLS_REJECT_UNAUTHORIZED=0
UMBRACO_INCLUDE_TOOL_COLLECTIONS=data-type,document-type,document,media-type,media
+6
View File
@@ -55,3 +55,9 @@
*.sln text=auto eol=crlf merge=union
*.gitattributes text=auto
# Generated files - hidden by default in GitHub diffs
src/Umbraco.Web.UI.Client/src/packages/core/backend-api/** linguist-generated
src/Umbraco.Web.UI.Login/src/api/** linguist-generated
templates/UmbracoExtension/Client/src/api/** linguist-generated
src/Umbraco.Cms.Api.Management/OpenApi.json linguist-generated
+1 -1
View File
@@ -30,7 +30,7 @@ This guide describes each step to make your first contribution:
Create a new branch based on `main` and name it after the issue you're fixing. For example: `v15/bugfix/18132-rte-tinymce-onchange-value-check`.
Please follow this format for branches: `v{major}/{feature|bugfix|task}/{issue}-{description}`.
Please follow this format for branches: `v{major}/{feature|bugfix|task|qa|improvement}/{issue}-{description}`.
This is a development branch for the particular issue you're working on, in this case, a bug-fix for issue number `18132` that affects Umbraco v.15.
+1 -1
View File
@@ -7,7 +7,7 @@ body:
id: "version"
attributes:
label: "Which Umbraco version are you using?"
description: "Please write the *exact* version, example: `10.1.0`. Use the help icon in the Umbraco backoffice to find the version you're using"
description: "Please write the *exact* version, example: `10.1.0`. Click the Umbraco logo in the top left corner of the backoffice to find the version you're using."
validations:
required: true
- type: textarea
+8
View File
@@ -38,6 +38,14 @@ Some important documentation links to get you started:
- [Getting to know Umbraco](https://docs.umbraco.com/umbraco-cms/fundamentals/get-to-know-umbraco)
- [Tutorials for creating a basic website and customizing the editing experience](https://docs.umbraco.com/umbraco-cms/tutorials/overview)
## Backoffice Preview
Want to see the latest backoffice UI in action? Check out our live preview:
**[backofficepreview.umbraco.com](https://backofficepreview.umbraco.com/)**
This preview is automatically deployed from the main branch and showcases the latest backoffice features and improvements. It runs from mock data and persistent edits are not supported.
## Get help
If you need a bit of feedback while building your Umbraco projects, we are [chatty on Discord](https://discord.umbraco.com). Our Discord server serves as a social space for all Umbracians. If you have any questions or need some help with a problem, head over to our [dedicated forum](https://forum.umbraco.com/) where the Umbraco Community will be happy to help.
+5 -5
View File
@@ -24,7 +24,7 @@ Great question! The short version goes like this:
1. **Switch to the correct branch**
Switch to the `contrib` branch
Switch to the `main` branch
1. **Build**
@@ -32,7 +32,7 @@ Great question! The short version goes like this:
1. **Branch**
Create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case issue number `12345`. Don't commit to `contrib`, create a new branch first.
Create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case issue number `12345`. Don't commit to `main`, create a new branch first.
1. **Change**
@@ -42,7 +42,7 @@ Great question! The short version goes like this:
Done? Yay! 🎉
Remember to commit to your new `temp` branch, and don't commit to `contrib`. Then you can push the changes up to your fork on GitHub.
Remember to commit to your new `temp` branch, and don't commit to `main`. Then you can push the changes up to your fork on GitHub.
#### Keeping your Umbraco fork in sync with the main repository
[sync fork]: #keeping-your-umbraco-fork-in-sync-with-the-main-repository
@@ -59,10 +59,10 @@ Then when you want to get the changes from the main repository:
```
git fetch upstream
git rebase upstream/contrib
git rebase upstream/main
```
In this command we're syncing with the `contrib` branch, but you can of course choose another one if needed.
In this command we're syncing with the `main` branch, but you can of course choose another one if needed.
[More information on how this works can be found on the thoughtbot blog.][sync fork ext]
+1 -1
View File
@@ -115,7 +115,7 @@ Save the changes and return to the Backoffice to see the update.
1. Commit your changes to a new temporary branch (avoid committing directly to `contrib`).
1. Commit your changes to a new temporary branch (avoid committing directly to `main`).
2. Push the changes to your fork on GitHub.
+1 -188
View File
@@ -1,188 +1 @@
# Umbraco CMS Development Guide
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
## Working Effectively
Bootstrap, build, and test the repository:
- Install .NET SDK (version specified in global.json):
- `curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --version $(jq -r '.sdk.version' global.json)`
- `export PATH="/home/runner/.dotnet:$PATH"`
- Install Node.js (version specified in src/Umbraco.Web.UI.Client/.nvmrc):
- `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash`
- `export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"`
- `nvm install $(cat src/Umbraco.Web.UI.Client/.nvmrc) && nvm use $(cat src/Umbraco.Web.UI.Client/.nvmrc)`
- Fix shallow clone issue (required for GitVersioning):
- `git fetch --unshallow`
- Restore packages:
- `dotnet restore` -- takes 50 seconds. NEVER CANCEL. Set timeout to 90+ seconds.
- Build the solution:
- `dotnet build` -- takes 4.5 minutes. NEVER CANCEL. Set timeout to 10+ minutes.
- Install and build frontend:
- `cd src/Umbraco.Web.UI.Client`
- `npm ci --no-fund --no-audit --prefer-offline` -- takes 11 seconds.
- `npm run build:for:cms` -- takes 1.25 minutes. NEVER CANCEL. Set timeout to 5+ minutes.
- Install and build Login
- `cd src/Umbraco.Web.UI.Login`
- `npm ci --no-fund --no-audit --prefer-offline`
- `npm run build`
- Run the application:
- `cd src/Umbraco.Web.UI`
- `dotnet run --no-build` -- Application runs on https://localhost:44339 and http://localhost:11000
Check out [BUILD.md](./BUILD.md) for more detailed instructions.
## Validation
- ALWAYS run through at least one complete end-to-end scenario after making changes.
- Build and unit tests must pass before committing changes.
- Frontend build produces output in src/Umbraco.Web.UI.Client/dist-cms/ which gets copied to src/Umbraco.Web.UI/wwwroot/umbraco/backoffice/
- Always run `dotnet build` and `npm run build:for:cms` before running the application to see your changes.
- For login-only changes, you can run `npm run build` from src/Umbraco.Web.UI.Login and then `dotnet run --no-build` from src/Umbraco.Web.UI.
- For frontend-only changes, you can run `npm run dev:server` from src/Umbraco.Web.UI.Client for hot reloading.
- Frontend changes should be linted using `npm run lint:fix` which uses Eslint.
## Testing
### Unit Tests (.NET)
- Location: tests/Umbraco.Tests.UnitTests/
- Run: `dotnet test tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj --configuration Release --verbosity minimal`
- Duration: ~1 minute with 3,343 tests
- NEVER CANCEL: Set timeout to 5+ minutes
### Integration Tests (.NET)
- Location: tests/Umbraco.Tests.Integration/
- Run: `dotnet test tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj --configuration Release --verbosity minimal`
- NEVER CANCEL: Set timeout to 10+ minutes
### Frontend Tests
- Location: src/Umbraco.Web.UI.Client/
- Run: `npm test` (requires `npx playwright install` first)
- Frontend tests use Web Test Runner with Playwright
### Acceptance Tests (E2E)
- Location: tests/Umbraco.Tests.AcceptanceTest/
- Requires running Umbraco application and configuration
- See tests/Umbraco.Tests.AcceptanceTest/README.md for detailed setup (requires `npx playwright install` first)
## Project Structure
The solution contains 30 C# projects organized as follows:
### Main Application Projects
- **Umbraco.Web.UI**: Main web application project (startup project)
- **Umbraco.Web.UI.Client**: TypeScript frontend (backoffice)
- **Umbraco.Web.UI.Login**: Separate login screen frontend
- **Umbraco.Core**: Core domain models and interfaces
- **Umbraco.Infrastructure**: Data access and infrastructure
- **Umbraco.Cms**: Main CMS package
### API Projects
- **Umbraco.Cms.Api.Management**: Management API
- **Umbraco.Cms.Api.Delivery**: Content Delivery API
- **Umbraco.Cms.Api.Common**: Shared API components
### Persistence Projects
- **Umbraco.Cms.Persistence.SqlServer**: SQL Server support
- **Umbraco.Cms.Persistence.Sqlite**: SQLite support
- **Umbraco.Cms.Persistence.EFCore**: Entity Framework Core abstractions
### Test Projects
- **Umbraco.Tests.UnitTests**: Unit tests
- **Umbraco.Tests.Integration**: Integration tests
- **Umbraco.Tests.AcceptanceTest**: End-to-end tests with Playwright
- **Umbraco.Tests.Common**: Shared test utilities
## Common Tasks
### Frontend Development
For frontend-only changes:
1. Configure backend for frontend development:
```json
<!-- Add to src/Umbraco.Web.UI/appsettings.json under Umbraco:Cms:Security: -->
```json
"BackOfficeHost": "http://localhost:5173",
"AuthorizeCallbackPathName": "/oauth_complete",
"AuthorizeCallbackLogoutPathName": "/logout",
"AuthorizeCallbackErrorPathName": "/error",
"BackOfficeTokenCookie": {
"SameSite": "None"
}
```
2. Run backend: `cd src/Umbraco.Web.UI && dotnet run --no-build`
3. Run frontend dev server: `cd src/Umbraco.Web.UI.Client && npm run dev:server`
### Backend-Only Development
For backend-only changes, disable frontend builds:
- Comment out the target named "BuildStaticAssetsPreconditions" in src/Umbraco.Cms.StaticAssets.csproj:
```
<!--<Target Name="BuildStaticAssetsPreconditions" BeforeTargets="AssignTargetPaths">
[...]
</Target>-->
```
- Remember to uncomment before committing
### Building NuGet Packages
To build custom NuGet packages for testing:
```bash
dotnet pack -c Release -o Build.Out
dotnet nuget add source [Path to Build.Out folder] -n MyLocalFeed
```
### Regenerating Frontend API Types
When changing Management API:
```bash
cd src/Umbraco.Web.UI.Client
npm run generate:server-api-dev
```
Also update OpenApi.json from /umbraco/swagger/management/swagger.json
## Database Setup
Default configuration supports SQLite for development. For production-like testing:
- Use SQL Server/LocalDb for better performance
- Configure connection string in src/Umbraco.Web.UI/appsettings.json
## Clean Up / Reset
To reset development environment:
```bash
# Remove configuration and database
rm src/Umbraco.Web.UI/appsettings.json
rm -rf src/Umbraco.Web.UI/umbraco/Data
# Full clean (removes all untracked files)
git clean -xdf .
```
## Version Information
- Target Framework: .NET (version specified in global.json)
- Current Version: (specified in version.json)
- Node.js Requirement: (specified in src/Umbraco.Web.UI.Client/.nvmrc)
- npm Requirement: Latest compatible version
## Known Issues
- Build requires full git history (not shallow clone) due to GitVersioning
- Some NuGet package security warnings are expected (SixLabors.ImageSharp vulnerabilities)
- Frontend tests require Playwright browser installation: `npx playwright install`
- Older Node.js versions may show engine compatibility warnings (check .nvmrc for current requirement)
## Timing Expectations
**NEVER CANCEL** these operations - they are expected to take time:
| Operation | Expected Time | Timeout Setting |
|-----------|--------------|-----------------|
| `dotnet restore` | 50 seconds | 90+ seconds |
| `dotnet build` | 4.5 minutes | 10+ minutes |
| `npm ci` | 11 seconds | 30+ seconds |
| `npm run build:for:cms` | 1.25 minutes | 5+ minutes |
| `npm test` | 2 minutes | 5+ minutes |
| `npm run lint` | 1 minute | 5+ minutes |
| Unit tests | 1 minute | 5+ minutes |
| Integration tests | Variable | 10+ minutes |
Always wait for commands to complete rather than canceling and retrying.
The full development guide for this repository lives in [CLAUDE.md](../CLAUDE.md). Please read that file for complete instructions on architecture, build steps, testing, branching conventions, and coding patterns.
+1 -3
View File
@@ -5,7 +5,6 @@ on:
branches:
- main
- v*/dev
- v*/main
paths:
- src/Umbraco.Web.UI.Client/package.json
- src/Umbraco.Web.UI.Client/package-lock.json
@@ -16,7 +15,6 @@ on:
branches:
- main
- v*/dev
- v*/main
workflow_dispatch:
jobs:
@@ -25,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
submodules: true
- name: Build And Deploy
+1 -3
View File
@@ -5,7 +5,6 @@ on:
branches:
- main
- v*/dev
- v*/main
paths:
- src/Umbraco.Web.UI.Client/package.json
- src/Umbraco.Web.UI.Client/package-lock.json
@@ -16,7 +15,6 @@ on:
branches:
- main
- v*/dev
- v*/main
workflow_dispatch:
env:
@@ -28,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
+88
View File
@@ -0,0 +1,88 @@
name: Claude PR Review
on:
pull_request:
types: [opened, ready_for_review, reopened]
# NOTE: `pull_request_target` would let this workflow review fork PRs
# (with access to secrets), but the action currently fails during OIDC
# token exchange with "401 Unauthorized - Invalid OIDC token" on that
# event. PR #579 added `pull_request_target` routing to the action, but
# Anthropic's `/github-app-token-exchange` endpoint appears not to
# accept the token claims produced by that event. Re-enable once the
# upstream issue is resolved.
# See: https://github.com/anthropics/claude-code-action/issues/347
# https://github.com/anthropics/claude-code-action/issues/621
# pull_request_target:
# types: [opened, ready_for_review]
permissions:
contents: read
pull-requests: write
id-token: write
actions: read
jobs:
review:
# Skip fork PRs: secrets are not exposed on `pull_request` events from
# forks, so the action would fail with a red check. Remove this clause
# once upstream fork support lands (tracked in
# https://github.com/anthropics/claude-code-action/issues/939) and we
# can re-enable the `pull_request_target` trigger above.
if: >-
github.event.pull_request.draft == false
&& github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_03 }}
# Enable progress tracking
track_progress: true
# Debug (set to true to show full output in logs, false to hide it and only post comments on the PR)
show_full_output: false
additional_permissions: "actions: read"
claude_args: "--model claude-sonnet-4-6 --allowedTools 'Bash(gh:*),Bash(git:*)'"
prompt: |
You are reviewing pull request #${{ github.event.pull_request.number }}
in the Umbraco CMS repository.
Read and execute the review procedure defined in `.claude/skills/umb-review/SKILL.md`.
For each finding that references a specific file and line:
- Post an individual inline PR comment on that line.
- Format: **[Severity]** explanation, then suggestion.
For the overall summary (header, impact, verdict):
- Post ONE top-level PR comment.
Do NOT use sticky/updating comments — post new individual comments.
After reviewing, apply labels to the PR based on changed files:
- `area/frontend` — if files under `src/Umbraco.Web.UI.Client/` are changed
- `area/backend` — if .cs files outside the frontend client are changed
- `area/test` — if only test files are changed
- `category/api` — if Management API or Delivery API files are changed
- `category/breaking` — if breaking changes were detected in the review
- `category/localization` — if localization/language files are changed
- `category/test-automation` — if only test files are changed
- `category/refactor` — if the PR is pure refactoring with no new features
- `category/performance` — if performance-related changes are detected
- `category/ux` — if user-facing changes are detected
- `category/ui` — if changes to the UI layer are detected
Only apply labels you are confident about. Never remove existing labels.
Be friendly and constructive. This project values community contributions.
Frame feedback as suggestions where possible.
Reserve firm language for genuine Critical issues only.
Run fully autonomously. Do NOT ask questions.
Only review changed files. Do not flag pre-existing issues.
Do not suggest changes that would themselves introduce breaking changes.
+91
View File
@@ -0,0 +1,91 @@
name: Claude
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned, labeled]
pull_request_review:
types: [submitted]
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_03 }}
assignee_trigger: "claude"
label_trigger: "claude"
base_branch: "main"
additional_permissions: "actions: read"
claude_args: "--model claude-sonnet-4-6 --max-turns 50 --allowedTools 'Bash(gh:*),Bash(git:*),Bash(npm:*),Bash(dotnet:*)'"
prompt: |
You are an AI assistant for the Umbraco CMS repository, an open-source
.NET CMS that welcomes community contributions.
You were triggered on issue/PR #${{ github.event.issue.number || github.event.pull_request.number }}.
Read the user's message and do what they ask. The trigger phrase
`@claude` is stripped before you see the message, so common requests
will look like:
- `review` — Review PR #${{ github.event.issue.number || github.event.pull_request.number }}.
Use `gh pr diff ${{ github.event.issue.number || github.event.pull_request.number }}`
and `gh pr view ${{ github.event.issue.number || github.event.pull_request.number }}`
to read the changes. Do NOT use git diff or the umb-review skill.
Focus on bugs, breaking changes, and architectural concerns.
Post inline comments for specific issues and a brief summary.
- `help` or a general question — Answer based on the codebase.
Read CLAUDE.md files for project structure and conventions.
- `fix ...` — Implement the requested fix on a new branch.
- `label` — Apply appropriate labels to the PR or issue.
If the message is empty or just whitespace, treat it as `review`
when on a PR, or `help` when on an issue.
If none of these match, read the user's message carefully and respond
to what they actually asked for.
## Labeling
When labeling PRs (based on changed files):
- `area/frontend`, `area/backend`, `area/test`
- `category/api`, `category/breaking`, `category/localization`
- `category/refactor`, `category/performance`, `category/ux`, `category/ui`
- `category/test-automation`
When labeling issues (based on content):
- `area/frontend`, `area/backend`, `area/test`
- `affected/v14` through `affected/v17`, `affected/backoffice`
- `category/api`, `category/localization`, `category/performance`
- `category/ux`, `category/ui`
Only apply labels you are confident about. Never remove existing labels.
## Tone
Be friendly and constructive. Frame feedback as suggestions.
Reserve firm language for genuine critical issues only.
## Constraints
- Run fully autonomously. Do NOT ask questions.
- Do not suggest changes that would introduce breaking changes.
+1 -1
View File
@@ -51,7 +51,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
# We use the setup-dotnet action to set up .NET Core, otherwise the CodeQL CLI will not work with preview versions.
- name: Setup .NET from global.json
+84
View File
@@ -0,0 +1,84 @@
name: Issue Deduplication
on:
issues:
types: [ opened ]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to analyze for duplicates'
required: true
type: number
jobs:
deduplicate:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
- name: Check for duplicate issues
uses: anthropics/claude-code-action@v1
with:
prompt: |
Analyze this new issue and check if it's a duplicate of existing issues in the repository.
Issue: #${{ github.event.issue.number || inputs.issue_number }}
Repository: ${{ github.repository }}
Your task:
1. Use mcp__github__get_issue to get details of the current issue (#${{ github.event.issue.number || inputs.issue_number }})
2. Search for similar existing issues using mcp__github__search_issues with relevant keywords from the issue title and body
3. Compare the new issue with existing ones to identify potential duplicates
Criteria for duplicates:
- Same bug or error being reported
- Same feature request (even if worded differently)
- Same question being asked
- Issues describing the same root problem
If you find duplicates:
- Add a comment on the new issue linking to the original issue(s)
- Apply the "duplicate" and "state/needs-investigation" labels to the new issue
- Be polite and explain why it's a duplicate
- Suggest the user follow the original issue for updates
If it's NOT a duplicate:
- Don't add any comments
- You may apply appropriate topic labels based on the issue content
Use these tools:
- mcp__github__get_issue: Get issue details
- mcp__github__search_issues: Search for similar issues
- mcp__github__list_issues: List recent issues if needed
- mcp__github__add_issue_comment: Add a comment if duplicate found
- mcp__github__update_issue: Add labels
Be thorough but efficient. Focus on finding true duplicates, not just similar issues.
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_03 }}
# Issues are opened by community members without write access, so the
# default OIDC token exchange fails with "User does not have write
# access on this repository". Pass `github_token` explicitly and set
# `allowed_non_write_users` to bypass that check. Safe here because
# `permissions:` and `--allowedTools` below are tightly scoped to
# issue operations only.
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: "*"
# Surface full SDK output (including tool calls and permission denials)
# to diagnose why Claude sometimes only partially completes (e.g. labels
# an issue but skips the comment). Safe to leave on — no secrets in output.
show_full_output: true
claude_args: |
--model claude-haiku-4-5 --allowedTools "mcp__github__get_issue,mcp__github__search_issues,mcp__github__list_issues,mcp__github__add_issue_comment,mcp__github__update_issue,mcp__github__get_issue_comments"
@@ -12,6 +12,7 @@ permissions:
jobs:
reconcile:
if: github.repository == 'umbraco/Umbraco-CMS'
runs-on: ubuntu-latest
steps:
- name: Reconcile release/* labels → discussions
@@ -52,7 +53,7 @@ jobs:
for (const item of items) {
const releaseLabels = (item.labels || [])
.map(l => (typeof l === "string" ? l : l.name)) // always get the name
.filter(n => typeof n === "string" && n.startsWith("release/"));
.filter(n => typeof n === "string" && n.startsWith("release/") && n !== "release/no-notes");
if (releaseLabels.length === 0) continue;
core.info(`#${item.number}: ${releaseLabels.join(", ")}`);
+99
View File
@@ -0,0 +1,99 @@
name: "SonarQube Cloud - Analysis"
# This workflow runs the full SonarCloud analysis with the SONAR_TOKEN secret.
# It is skipped for fork PRs since secrets are not available in that context.
on:
push:
branches:
- main
- "v*/dev"
- "v*/main"
- "release/*"
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
permissions:
contents: read
env:
SONAR_PROJECT_KEY: umbraco_Umbraco-CMS
SONAR_ORGANIZATION: umbraco
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
analyze:
name: Build and analyze
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork != true
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup .NET from global.json
uses: actions/setup-dotnet@v5
- name: Setup Java 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: "21"
- name: Cache SonarQube packages
uses: actions/cache@v5
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Install tools
run: |
dotnet tool install --global dotnet-sonarscanner
dotnet tool install --global dotnet-coverage
- name: Load sonar params
run: echo "SONARQUBE_SCANNER_PARAMS=$(jq -c . .github/workflows/sonarcloud/sonar-params.json)" >> $GITHUB_ENV
- name: Begin analysis
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
dotnet-sonarscanner begin \
/k:"$SONAR_PROJECT_KEY" \
/o:"$SONAR_ORGANIZATION" \
/d:sonar.token="$SONAR_TOKEN" \
/d:sonar.scanner.skipJreProvisioning=true
- name: Restore
run: dotnet restore umbraco.sln
- name: Build solution
run: GITHUB_ENV=/dev/null dotnet build umbraco.sln --no-restore -clp:ErrorsOnly # prevent sonar MSBuild integration from writing malformed values to $GITHUB_ENV
- name: Run unit tests with coverage
id: tests
continue-on-error: true
run: |
dotnet-coverage collect \
"dotnet test tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj --no-build" \
--output TestResults/coverage.xml \
--output-format xml
- name: Warn on test failure
if: steps.tests.outcome == 'failure'
run: |
if [ -f TestResults/coverage.xml ]; then
echo "::warning::Unit tests failed - SonarCloud analysis will proceed with the collected coverage data"
else
echo "::warning::Unit tests failed and no coverage data was collected"
fi
- name: End analysis
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: dotnet-sonarscanner end /d:sonar.token="$SONAR_TOKEN"
@@ -0,0 +1,7 @@
{
"sonar.cs.vscoveragexml.reportsPaths": "TestResults/coverage.xml",
"sonar.inclusions": "src/**,templates/**,tools/**,tests/**,.github/**,build/**",
"sonar.exclusions": "**/bin/**,**/obj/**,**/node_modules/**,**/lang/*.ts,**/mocks/**,**/wwwroot/**,**/dist-cms/**,**/*.generated.cs,src/Umbraco.Web.UI/umbraco/**,src/Umbraco.Cms.Persistence.EFCore.*/Migrations/**,src/Umbraco.Web.UI.Client/src/packages/core/backend-api/**,**/.nuget/**",
"sonar.test.inclusions": "tests/**,**/*.test.ts,**/*.spec.ts",
"sonar.typescript.tsconfigPaths": "src/Umbraco.Web.UI.Client/tsconfig.json,src/Umbraco.Web.UI.Client/tsconfig.node.json,src/Umbraco.Web.UI.Login/tsconfig.json"
}
+2 -2
View File
@@ -34,7 +34,7 @@ jobs:
run:
working-directory: src/Umbraco.Web.UI.Client
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Use Node.js
uses: actions/setup-node@v4
with:
@@ -57,7 +57,7 @@ jobs:
run:
working-directory: src/Umbraco.Web.UI.Client
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Use Node.js
uses: actions/setup-node@v4
with:
+18 -3
View File
@@ -51,6 +51,12 @@ tools/docfx/
/build/csharp-docs/api/
/build/csharp-docs/_site/
# Local config
.claude/*
!.claude/skills/
!.claude/settings.json
.env.local
# Build
/build.out/
/build.tmp/
@@ -66,7 +72,8 @@ tools/docfx/
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/js
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/lib
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/views
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/views/*
!/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/views/errors
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/login
# Environment specific data
@@ -95,6 +102,11 @@ tools/docfx/
/tests/Umbraco.Tests.Integration/[Uu]mbraco/[Ll]ogs/
/tests/Umbraco.Tests.Integration/Views/
/tests/Umbraco.Tests.UnitTests/[Uu]mbraco/[Dd]ata/TEMP/
/BenchmarkDotNet.Artifacts/
playwright-report
trace.zip
/tests/Umbraco.Tests.AcceptanceTest/results
/tests/Umbraco.Tests.AcceptanceTest/dist
# Ignore auto-generated schema
/src/Umbraco.Cms.Targets/tasks/
@@ -103,9 +115,12 @@ tools/docfx/
/src/Umbraco.Web.UI/appsettings-schema.json
/src/Umbraco.Web.UI/appsettings-schema.*.json
/src/Umbraco.Web.UI/umbraco-package-schema.json
/src/Umbraco.Web.UI.Client/umbraco-package-schema.json
/tests/Umbraco.Tests.Integration/appsettings-schema.json
/tests/Umbraco.Tests.Integration/appsettings-schema.*.json
/tests/Umbraco.Tests.Integration/umbraco-package-schema.json
/src/Umbraco.Cms/appsettings-schema.json
playwright-report
trace.zip
.playwright-mcp/
# SonarQube local analysis cache
.sonarqube/
-1
View File
@@ -48,7 +48,6 @@ dotnet_analyzer_diagnostic.category-StyleCop.CSharp.OrderingRules.severity = sug
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.MaintainabilityRules.severity = suggestion
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.LayoutRules.severity = suggestion
dotnet_diagnostic.SA1636.severity = none # SA1636: File header copyright text should match
dotnet_diagnostic.SA1101.severity = none # PrefixLocalCallsWithThis - stylecop appears to be ignoring dotnet_style_qualification_for_*
dotnet_diagnostic.SA1309.severity = none # FieldNamesMustNotBeginWithUnderscore
+14
View File
@@ -0,0 +1,14 @@
{
"mcpServers": {
"umbraco-cms": {
"command": "npx",
"args": ["@umbraco-cms/mcp-dev@17"]
},
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
}
}
}
+1
View File
@@ -101,6 +101,7 @@
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "https://localhost:44339",
"UMBRACO__CMS__WEBROUTING__UMBRACOAPPLICATIONURL": "https://localhost:44339",
"UMBRACO__CMS__SECURITY__BACKOFFICEHOST": "http://localhost:5173",
"UMBRACO__CMS__SECURITY__AUTHORIZECALLBACKPATHNAME": "/oauth_complete",
"UMBRACO__CMS__SECURITY__AUTHORIZECALLBACKLOGOUTPATHNAME": "/logout",
+1
View File
@@ -3,6 +3,7 @@
"backoffice",
"pickable",
"Pickable",
"Umbraco",
"unprovide",
"Unproviding"
],
+635
View File
@@ -0,0 +1,635 @@
# Umbraco CMS - Multi-Project Repository
Enterprise-grade CMS built on .NET 10.0. This repository contains 21 production projects organized in a layered architecture with clear separation of concerns.
**Repository**: https://github.com/umbraco/Umbraco-CMS
**License**: MIT
**Main Branch**: `main`
---
## 1. Overview
### What This Repository Contains
**21 Production Projects** organized in 3 main categories:
1. **Core Architecture** (Domain & Infrastructure)
- `Umbraco.Core` - Interface contracts, domain models, notifications
- `Umbraco.Infrastructure` - Service implementations, data access, caching
2. **Web & APIs** (Presentation Layer)
- `Umbraco.Web.UI` - Main ASP.NET Core web application
- `Umbraco.Web.Common` - Shared web functionality, controllers, middleware
- `Umbraco.Cms.Api.Management` - Backoffice Management API (REST)
- `Umbraco.Cms.Api.Delivery` - Content Delivery API (headless)
- `Umbraco.Cms.Api.Common` - Shared API infrastructure
3. **Specialized Features** (Pluggable Modules)
- Persistence: EF Core (modern), NPoco (legacy) for SQL Server & SQLite
- Caching: `PublishedCache.HybridCache` (in-memory + distributed)
- Search: `Examine.Lucene` (full-text search)
- Imaging: `Imaging.ImageSharp` v1 & v2 (image processing)
- Other: Static assets, targets, development tools
**6 Test Projects**:
- `Umbraco.Tests.Common` - Shared test utilities
- `Umbraco.Tests.UnitTests` - Unit tests
- `Umbraco.Tests.Integration` - Integration tests
- `Umbraco.Tests.Benchmarks` - Performance benchmarks
- `Umbraco.Tests.AcceptanceTest` - E2E tests
- `Umbraco.Tests.AcceptanceTest.UmbracoProject` - Test instance
### Key Technologies
- **.NET 10.0** - Target framework for all projects
- **ASP.NET Core** - Web framework
- **Entity Framework Core** - Modern ORM
- **OpenIddict** - OAuth 2.0/OpenID Connect authentication
- **Microsoft.AspNetCore.OpenApi** - OpenAPI document generation
- **Swashbuckle.AspNetCore.SwaggerUI** - Swagger UI for API documentation
- **Lucene.NET** - Full-text search via Examine
- **ImageSharp** - Image processing
---
## 2. Repository Structure
```
Umbraco-CMS/
├── src/ # 21 production projects
│ ├── Umbraco.Core/ # Domain contracts (interfaces only)
│ │ └── CLAUDE.md # ⭐ Core architecture guide
│ ├── Umbraco.Infrastructure/ # Service implementations
│ ├── Umbraco.Web.Common/ # Web utilities
│ ├── Umbraco.Web.UI/ # Main web application
│ ├── Umbraco.Cms.Api.Management/ # Management API
│ ├── Umbraco.Cms.Api.Delivery/ # Delivery API (headless)
│ ├── Umbraco.Cms.Api.Common/ # Shared API infrastructure
│ │ └── CLAUDE.md # ⭐ API patterns guide
│ ├── Umbraco.PublishedCache.HybridCache/ # Content caching
│ ├── Umbraco.Examine.Lucene/ # Search indexing
│ ├── Umbraco.Cms.Persistence.EFCore/ # EF Core data access
│ ├── Umbraco.Cms.Persistence.EFCore.Sqlite/
│ ├── Umbraco.Cms.Persistence.EFCore.SqlServer/
│ ├── Umbraco.Cms.Persistence.Sqlite/ # Legacy SQLite
│ ├── Umbraco.Cms.Persistence.SqlServer/ # Legacy SQL Server
│ ├── Umbraco.Cms.Imaging.ImageSharp/ # Image processing v1
│ ├── Umbraco.Cms.Imaging.ImageSharp2/ # Image processing v2
│ ├── Umbraco.Cms.StaticAssets/ # Embedded assets
│ ├── Umbraco.Cms.DevelopmentMode.Backoffice/
│ ├── Umbraco.Cms.Targets/ # NuGet targets
│ └── Umbraco.Cms/ # Meta-package
├── tests/ # 6 test projects
│ ├── Umbraco.Tests.Common/
│ ├── Umbraco.Tests.UnitTests/
│ ├── Umbraco.Tests.Integration/
│ ├── Umbraco.Tests.Benchmarks/
│ ├── Umbraco.Tests.AcceptanceTest/
│ └── Umbraco.Tests.AcceptanceTest.UmbracoProject/
├── templates/ # Project templates
│ └── Umbraco.Templates/
├── tools/ # Build tools
│ └── Umbraco.JsonSchema/
├── umbraco.sln # Main solution file
├── Directory.Build.props # Shared build configuration
├── Directory.Packages.props # Centralized package versions
├── .editorconfig # Code style
└── .globalconfig # Roslyn analyzers
```
### Architecture Layers
**Dependency Flow** (unidirectional, always flows inward):
```
Web.UI → Web.Common → Infrastructure → Core
Api.Management → Api.Common → Infrastructure → Core
Api.Delivery → Api.Common → Infrastructure → Core
```
**Key Principle**: Core has NO dependencies (pure contracts). Infrastructure implements Core. Web/APIs depend on Infrastructure.
### Project Dependencies
**Core Layer**:
- `Umbraco.Core` → No dependencies (only Microsoft.Extensions.*)
**Infrastructure Layer**:
- `Umbraco.Infrastructure``Umbraco.Core`
- `Umbraco.PublishedCache.*``Umbraco.Infrastructure`
- `Umbraco.Examine.Lucene``Umbraco.Infrastructure`
- `Umbraco.Cms.Persistence.*``Umbraco.Infrastructure`
**Web Layer**:
- `Umbraco.Web.Common``Umbraco.Infrastructure` + caching + search
- `Umbraco.Web.UI``Umbraco.Web.Common` + all features
**API Layer**:
- `Umbraco.Cms.Api.Common``Umbraco.Web.Common`
- `Umbraco.Cms.Api.Management``Umbraco.Cms.Api.Common`
- `Umbraco.Cms.Api.Delivery``Umbraco.Cms.Api.Common`
---
## 3. Teamwork & Collaboration
### Branching Strategy
- **Main branch**: `main` (protected)
- **Branch naming convention**: `v<version>/<type>/<description>`
**Format**: `v{major-version}/{type}/{kebab-case-description}`
**Version**: Read from `version.json` in the repository root. Use the major version number (e.g., `v17` for version 17.x.x).
**Types**:
| Type | Use Case |
|------|----------|
| `feature` | New feature being introduced to the product |
| `bugfix` | Fix to an existing issue with the product |
| `qa` | Adding or updating unit, integration, or end-to-end tests |
| `improvement` | Update to something that already exists but isn't broken (UI finessing, refactoring) |
| `task` | Update that doesn't directly impact product behavior (dependency updates, build pipeline) |
**Description**: A short, kebab-case description (a few words). This should be prefixed with the GitHub issue number if the update is related to resolving a tracked issue.
**Examples**:
```
v17/bugfix/12345-correct-display-of-pending-migrations
v17/feature/add-webhook-support
v17/improvement/optimize-content-cache
v17/qa/add-media-service-tests
v17/task/update-ef-core-dependency
```
See `.github/CONTRIBUTING.md` for full guidelines.
### Pull Request Process
- **PR Template**: `.github/pull_request_template.md`
- **Required CI Checks**:
- All tests pass
- Code formatting (dotnet format)
- No build warnings
- **Merge Strategy**: Squash and merge (via GitHub UI)
- **Reviews**: Required from code owners
#### PR Naming Convention
Use the format: `Area: Description (closes #IssueID)`
**Examples**:
| Area | Description | Issue |
|------|-------------|-------|
| Relations: | Move persistence of relations from repository into notification handlers | (closes #00000) |
| Management API: | Correct the population of the parent for sibling items when retrieved under a folder | |
| Docs: | Updated contributing guidelines to welcome contributions on bugfixes | |
**Area**: The feature or aspect affected (e.g., UFM, TipTap, Docs, Segmentation, Migrations). Helps readers quickly understand what is being changed.
**Description Best Practices**:
- Include the area of change (Relations, Management API, etc.)
- Describe the change and its impact
- Be specific, not vague (describe "a golden retriever" not just "a dog")
**Issue Linking**: Add `(closes #IssueID)` to the title for readability, AND include a closing keyword on its own line in the PR body (e.g., `Fixes #IssueID`) so GitHub actually auto-links and auto-closes the issue on merge. GitHub only parses closing keywords (`closes`, `fixes`, `resolves`) from the PR body or commit messages — the title suffix is cosmetic and does **not** trigger auto-close on its own.
### Commit Messages
Follow Conventional Commits format:
```
<type>(<scope>): <description>
Types: feat, fix, docs, style, refactor, test, chore
Scope: project name (core, web, api, etc.)
Examples:
feat(core): add IContentService.GetByIds method
fix(api): resolve null reference in schema handler
docs(web): update routing documentation
```
### Code Owners
Project ownership is distributed across teams. Check individual project directories for ownership.
---
## 4. Architecture Patterns
### Core Architectural Decisions
1. **Layered Architecture with Dependency Inversion**
- Core defines contracts (interfaces)
- Infrastructure implements contracts that need Infrastructure-owned machinery
- Web/APIs consume implementations via DI
**Where service implementations live**: Services whose dependencies are satisfiable from Core interfaces alone (repositories, scope, config, other Core services) live in `Umbraco.Core/Services/` — this covers the majority of domain services (`MemberService`, `ContentService`, `MediaService`, `ContentTypeService`, `EntityService`, `AuditService`, `ExternalMemberService`, etc.). Service implementations only live in `Umbraco.Infrastructure/Services/Implement/` when they genuinely need Infrastructure concerns — Examine indexes (`ContentSearchService`, `MediaSearchService`, `IndexedEntitySearchService`), log files (`LogViewerRepository`), packaging internals (`PackagingService`), webhook firing (`WebhookFiringService`), distributed-job coordination (`DistributedJobService`). When adding a new service, default to Core and only move to Infrastructure if a concrete dependency forces it.
2. **Interface-First Design**
- All services defined as interfaces in Core
- Enables testing, polymorphism, extensibility
3. **Notification Pattern** (not C# events)
- See `/src/Umbraco.Core/CLAUDE.md` → "2. Notification System (Event Handling)"
4. **Composer Pattern** (DI registration)
- See `/src/Umbraco.Core/CLAUDE.md` → "3. Composer Pattern (DI Registration)"
5. **Scoping Pattern** (Unit of Work)
- See `/src/Umbraco.Core/CLAUDE.md` → "5. Scoping Pattern (Unit of Work)"
6. **Attempt Pattern** (operation results)
- `Attempt<TResult, TStatus>` instead of exceptions
- Strongly-typed operation status enums
### Key Design Patterns Used
- **Repository Pattern** - Data access abstraction
- **Unit of Work** - Scoping for transactions
- **Builder Pattern** - `ProblemDetailsBuilder` for API errors
- **Strategy Pattern** - OpenAPI handlers (schema ID, operation ID)
- **Options Pattern** - All configuration via `IOptions<T>`
- **Factory Pattern** - Content type factories
- **Mediator Pattern** - Notification aggregator
---
## 5. Avoiding Breaking Changes
No binary breaking changes are allowed within a major version. Three patterns are used:
### 5.1 Obsolete Constructor + StaticServiceProvider
When a public class needs new dependencies, obsolete the existing constructor and add a new one. The old constructor delegates to the new one, resolving missing deps via `StaticServiceProvider`.
```csharp
[Obsolete("Please use the constructor with all parameters. Scheduled for removal in Umbraco 19.")]
public MyService(IDependencyA depA)
: this(
depA,
StaticServiceProvider.Instance.GetRequiredService<IDependencyB>())
{
}
public MyService(IDependencyA depA, IDependencyB depB)
{
_depA = depA;
_depB = depB;
}
```
**Examples**:
- `ContentCollectionPresentationFactory` - added `FlagProviderCollection`
- `CacheInstructionService` - added `ILastSyncedManager`, `IRepositoryCacheVersionService`
- `DocumentPresentationFactory` - added `FlagProviderCollection`
**Rules**:
- Old constructor marked `[Obsolete("... Scheduled for removal in Umbraco {current-major+2}.")]`
- Old constructor calls new constructor via `: this(...)`
- Uses `StaticServiceProvider.Instance.GetRequiredService<T>()` for new params only
- DI registration must use the NEW constructor (old is for external consumers only)
### 5.2 Obsolete Method + New Overload
When a public method signature needs to change, add the new method/overload and obsolete the old. The obsolete method should call the new one with suitable defaults.
```csharp
[Obsolete("Use the overload taking all parameters. Scheduled for removal in Umbraco 19.")]
public void DoThing(string name)
=> DoThing(name, extraParam: null);
public void DoThing(string name, string? extraParam)
{
// Real implementation here
}
```
**Rules**:
- Old method marked `[Obsolete]` with removal schedule
- DRY: old method calls new method, providing defaults for new parameters
- All internal callers must be updated to use the new method
- No callers should remain on the obsolete method within the codebase
### 5.3 Default Interface Implementation
When adding methods to a public interface, provide a default implementation so existing external implementations don't break.
```csharp
public interface IMyService
{
// Existing method
void ExistingMethod();
// New method with default implementation
void NewMethod(string param)
=> ExistingMethod(); // delegate to existing if possible
}
```
**Strategies for the default** (in order of preference):
1. **Use existing interface methods** to satisfy the contract (even if not optimal)
2. **Return a sensible default** like empty collection, null, etc.
3. **Throw `NotImplementedException`** if no reasonable default exists
**Example**: `IContentService.SaveBlueprint` - new overload with `IContent? createdFromContent` has a default impl that calls the old method (ignoring the new param).
**Example**: `IDocumentPresentationFactory.CreateCulturePublishScheduleModels` - full default implementation with logic, uses `StaticServiceProvider` for dependency resolution within the interface.
**Rules**:
- Add `// TODO (V{next-major}): Remove the default implementation when {obsolete method} is removed.` comment
- Default impl should be functionally correct even if not optimal
- If using `StaticServiceProvider` in a default impl, note this is temporary
### 5.4 General Rules
- **Removal policy**: Obsoleted members must remain for at least one full major version before removal. If obsoleted in version N, the earliest removal is version N+2. For example, something obsoleted in v17 is scheduled for removal in v19 (giving the whole of v18 as a deprecation period).
- All `[Obsolete]` attributes must include **"Scheduled for removal in Umbraco {current+2}"**
- Read `version.json` to determine the current major version
- Suppress `CS0618` warnings where obsolete members must call each other:
```csharp
#pragma warning disable CS0618 // Type or member is obsolete
=> OldMethod(param);
#pragma warning restore CS0618 // Type or member is obsolete
```
- Update ALL internal callers to use the new API - no internal code should use obsolete members
---
## 6. Project-Specific Notes
### Centralized Package Management
**NuGet package versions** are centralized in `Directory.Packages.props`. There are two `Directory.Packages.props` files in the source tree, with multi-level merging enabled so the test file inherits from the root:
| File | Scope |
|------|-------|
| `Directory.Packages.props` (root) | Production source code packages — referenced by all `src/**` projects |
| `tests/Directory.Packages.props` | Test-only packages (NUnit, Moq, Bogus, BenchmarkDotNet, etc.) — adds entries on top of the inherited root file |
When updating dependencies, decide which file the package belongs in:
- A package used only by test projects → `tests/Directory.Packages.props`
- A package used by any production project (or by both production and tests) → root `Directory.Packages.props`
```xml
<!-- Individual projects reference WITHOUT version -->
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<!-- Versions defined in Directory.Packages.props -->
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
```
**Opt-out**: `src/Umbraco.Web.UI/Umbraco.Web.UI.csproj` sets `<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>` and specifies versions inline (for `Microsoft.EntityFrameworkCore.Design`, `Microsoft.Build.Tasks.Core`, `Microsoft.ICU.ICU4C.Runtime`, etc.). Update those versions directly in that csproj when bumping. Two further `Directory.Packages.props` files exist under `templates/` for the project/extension templates and have their own version sets — keep `Microsoft.AspNetCore.OpenApi` aligned between the root file and `templates/UmbracoExtension/`.
### Build Configuration
- `Directory.Build.props` - Shared properties (target framework, company, copyright)
- `.editorconfig` - Code style rules
- `.globalconfig` - Roslyn analyzer rules
### Persistence Layer - NPoco and EF Core
The repository contains BOTH (actively supported):
- **Current**: NPoco-based persistence (`Umbraco.Cms.Persistence.Sqlite`, `Umbraco.Cms.Persistence.SqlServer`) - widely used and fully supported
- **Future**: EF Core-based persistence (`Umbraco.Cms.Persistence.EFCore.*`) - migration in progress
**Note**: The codebase is actively migrating to EF Core, but NPoco remains the primary persistence layer and is not deprecated. Both are fully supported.
### Authentication: OpenIddict
All APIs use **OpenIddict** (OAuth 2.0/OpenID Connect):
- Reference tokens (not JWT) for better security
- **Secure cookie-based token storage** (v17+) - tokens stored in HTTP-only cookies with `__Host-` prefix
- Tokens are redacted from client-side responses and passed via secure cookies only (`[redacted]` placeholder)
- ASP.NET Core Data Protection for token encryption
- Configured in `Umbraco.Cms.Api.Common`
- API requests must include credentials (`credentials: include` for fetch)
**Load Balancing Requirement**: All servers must share the same Data Protection key ring.
**Frontend auth pitfalls** — see `src/Umbraco.Web.UI.Client/docs/edge-cases.md` (Auth & Cross-tab section) and `docs/security.md`. Key points:
- Never call `validateToken()` per API request — it revokes the previous reference token (ID2019 errors)
- `window.opener` is set for ANY `window.open()` target, not only OAuth popups — scope guards to the pathname too
- BroadcastChannel does not deliver messages to the sender's own tab
### Content Caching Strategy
**HybridCache** (`Umbraco.PublishedCache.HybridCache`):
- In-memory cache + distributed cache support
- Published content only (not draft)
- Invalidated via notifications and cache refreshers
### API Versioning
APIs use `Asp.Versioning.Mvc`:
- Management API: `/umbraco/management/api/v{version}/*`
- Delivery API: `/umbraco/delivery/api/v{version}/*`
- OpenAPI docs: `/umbraco/openapi/management.json`, `/umbraco/openapi/delivery.json`
- Swagger UI: `/umbraco/openapi/`
### Updating `OpenApi.json` (Management API)
When a PR changes Management API controllers or models, the `OpenApi.json` file in the Management API project must be updated:
1. Run the Umbraco instance locally
2. Open Swagger UI and navigate to the swagger.json link (e.g. `https://localhost:44339/umbraco/swagger/management/swagger.json`)
3. Copy the full JSON content and paste it into `src/Umbraco.Cms.Api.Management/OpenApi.json`
**Important**: Commit only the substantive changes — not IDE-applied formatting (whitespace, reordering, etc.). Extraneous formatting diffs make PRs harder to review and merge-ups more error-prone.
### Backoffice npm Package
The backoffice is published to npm as `@umbraco-cms/backoffice`. Runtime dependencies are provided via importmap; npm peerDependencies provide types only. For full details on dependency hoisting, version range logic, and plugin development, see `/src/Umbraco.Web.UI.Client/CLAUDE.md` → "npm Package Publishing".
### SQL Server 2100-parameter limit
Any `WHERE IN (@0, @1, ...)` built from a runtime-sized collection risks hitting SQL Server's 2100-parameter ceiling and throwing `SqlException` 8003 in production.
Batch with `IEnumerable<T>.InGroupsOf(Constants.Sql.MaxParameterCount)` or `Database.FetchByGroups(...)` whenever the collection size is driven by user data — not just when it currently fits. Watch for products of two scaling dimensions (documents × languages, properties × versions) and config-tunable batch sizes whose defaults are safe but ceilings aren't.
Full guidance, safe patterns and decision rule: see `/src/Umbraco.Infrastructure/CLAUDE.md` → "Avoiding the SQL Server 2100-parameter limit".
### Known Limitations
1. **Circular Dependencies**: Avoided via `Lazy<T>` or event notifications
2. **Multi-Server**: Requires shared Data Protection key ring and synchronized clocks (NTP)
3. **Database Support**: SQL Server, SQLite
---
## 7. CI/CD — Claude AI Assistant
Two GitHub Actions workflows powered by `anthropics/claude-code-action@v1`. Advisory only — does not block merging.
### Workflows
| File | Trigger | Purpose |
|------|---------|---------|
| `claude-review.yml` | `pull_request: [opened, ready_for_review]` | Auto-review every non-draft PR using the `umb-review` skill |
| `claude.yml` | `@claude` comments, issue assign/label | Interactive assistant for PRs and issues |
### Auto-Review (`claude-review.yml`)
Runs the full `.claude/skills/umb-review/SKILL.md` procedure on every newly opened or un-drafted PR. Produces inline comments per finding and one summary comment with a verdict. Skips draft PRs. No turn limit.
### Interactive (`claude.yml`)
Responds to `@claude` mentions on PRs and issues. The trigger phrase is stripped before Claude sees the message, so:
- `@claude review` → light review using `gh pr diff` (not the umb-review skill)
- `@claude fix ...` → implements a fix on a new branch
- `@claude help` → answers questions about the codebase
- `@claude label` → applies labels
- `@claude` (empty) → defaults to `review` on PRs, `help` on issues
Also triggers on issue assignment to `claude` or adding the `claude` label. Gated: only runs when `@claude` appears in the comment/issue body. Max 25 turns.
**Allowed Bash tools**: `gh`, `git`, `npm`, `dotnet` (interactive only; auto-review allows `gh` and `git`).
### Labels
Both workflows apply labels based on content:
**On PRs** (based on changed files):
| Label | Condition |
|-------|-----------|
| `area/frontend` | Files under `src/Umbraco.Web.UI.Client/` |
| `area/backend` | `.cs` files outside the frontend client |
| `area/test` | Only test files changed |
| `category/api` | Management or Delivery API files |
| `category/breaking` | Breaking changes detected |
| `category/localization` | Localization/language files |
| `category/test-automation` | Only test files changed |
| `category/refactor` | Pure refactoring, no new features |
| `category/performance` | Performance-related changes |
| `category/ux` | User-facing changes |
| `category/ui` | UI layer changes |
**On Issues** (based on content): same `area/*` and `category/*` labels, plus `affected/v14` through `affected/v17` and `affected/backoffice`.
Labels are only added, never removed. Claude applies only labels it is confident about.
### Key Implementation Notes
- **Checkout required** — the action internally runs `git fetch origin main` for trusted file restoration. Without `actions/checkout`, it fails with `fatal: not a git repository`.
- **`id-token: write` permission** — required for OIDC token exchange with the Claude GitHub App.
- **Trigger phrase stripping** — the action strips `@claude` from comments before passing to Claude. Prompts must reference commands without the prefix (e.g., `review` not `@claude review`).
- **PR number injection** — the interactive workflow injects the PR/issue number into the prompt via `${{ github.event.issue.number }}` since Claude can't discover it from `gh pr view` when checked out on `main`.
---
## 8. Code Comment Policy
**Default to no comment.** Applies to all code in this repository — C#, TypeScript, Razor, build scripts. Well-named identifiers and small functions are the primary form of self-documentation; comments are a fallback for the rare cases where the code itself cannot carry the meaning.
### When NOT to comment
- **Don't restate what the code does.** A line calling `resetState()` does not need `// Reset state`. A method named `validateInput` does not need `// Validate input`.
- **Don't narrate a sequence of calls.** If three lines run in order, the order is in the code — don't paraphrase it above.
- **Don't reference the current task, fix, callers, or PR.** No `// Fix for X`, `// Used by Y`, `// Added for the Z flow`, `// See PR #1234`. That belongs in commit messages and PR descriptions; in source it rots as the codebase evolves.
### When a comment IS justified
Write a comment only when **removing it would leave a future reader confused**. Concretely:
- **A non-obvious WHY.** A hidden constraint, business rule, or ordering requirement that is not visible from the code.
- **A workaround for a specific bug or platform quirk.** Link the issue (`(#21996)`, `https://...`) so the comment can be deleted once the upstream fix lands.
- **A subtle invariant** that the type system or method names do not enforce.
- **An edge case the code intentionally handles** that would surprise a reader (e.g. "must run before X because Y").
- **API documentation** — XML doc comments on C# members, JSDoc on exported TypeScript symbols. Required for the public contract; still keep them concise.
### TODOs
Allowed, but cheap to write and cheaper to leave behind. Keep them short and trackable: `// TODO (V19): remove once obsolete overload is gone` or `// TODO: pagination [NL]`. A TODO should have an author or a version trigger.
---
## 9. Testing Practices
### Tests for a bug fix must fail before the fix
Verify any test you add for a bug fix actually catches the bug: either write the failing test first (TDD), or temporarily revert the production change and confirm the test fails before re-applying. A test that passes both ways proves nothing. Watch for coincidental passes — default seed/sort orders can make a buggy path produce the right answer for the test's specific inputs; construct inputs so the broken and fixed behaviours give visibly different results.
For integration tests that exercise caching or cache refreshers, see `tests/Umbraco.Tests.Integration/CLAUDE.md` — the harness disables caching by default, which can produce false greens.
---
## Quick Reference
### Essential Commands
```bash
# Build solution
dotnet build
# Run all tests
dotnet test
# Run specific test category
dotnet test --filter "Category=Integration"
# Format code
dotnet format
# Pack all projects
dotnet pack -c Release
```
### Integration Test Database Configuration
Integration tests are configured in `tests/Umbraco.Tests.Integration/appsettings.Tests.json`.
The `Tests:Database:DatabaseType` setting controls which database is used:
- `"SQLite"` (default) - No external dependencies
- `"LocalDb"` - Uses SQL Server LocalDB, required for SQL Server-specific tests (e.g., page-level locking, `sys.dm_tran_locks`)
SQL Server-specific tests use `BaseTestDatabase.IsSqlite()` to skip when running on SQLite.
### Key Projects
| Project | Type | Description |
|---------|------|-------------|
| **Umbraco.Core** | Library | Interface contracts and domain models |
| **Umbraco.Infrastructure** | Library | Service implementations and data access |
| **Umbraco.Web.UI** | Application | Main web application (Razor/MVC) |
| **Umbraco.Cms.Api.Management** | Library | Management API (backoffice) |
| **Umbraco.Cms.Api.Delivery** | Library | Delivery API (headless CMS) |
| **Umbraco.Cms.Api.Common** | Library | Shared API infrastructure |
| **Umbraco.PublishedCache.HybridCache** | Library | Published content caching |
| **Umbraco.Examine.Lucene** | Library | Full-text search indexing |
### Important Files
- **Solution**: `umbraco.sln`
- **Build Config**: `Directory.Build.props`, `Directory.Packages.props`
- **Code Style**: `.editorconfig`, `.globalconfig`
- **Documentation**: `/CLAUDE.md`, `/src/Umbraco.Core/CLAUDE.md`, `/src/Umbraco.Cms.Api.Common/CLAUDE.md`
### Project-Specific Documentation
For detailed information about individual projects, see their CLAUDE.md files:
- **Core Architecture**: `/src/Umbraco.Core/CLAUDE.md` - Service contracts, notification patterns
- **API Infrastructure**: `/src/Umbraco.Cms.Api.Common/CLAUDE.md` - OpenAPI, authentication, serialization
- **Backoffice Frontend**: `/src/Umbraco.Web.UI.Client/CLAUDE.md` - Lit web components, extension system, auth client
**Important**: When working on backoffice client code (anything under `src/Umbraco.Web.UI.Client/`), read `/src/Umbraco.Web.UI.Client/CLAUDE.md` first. It contains action-specific checklists (deprecation, testing, security, etc.) that are not duplicated here.
### Getting Help
- **Official Docs**: https://docs.umbraco.com/
- **Contributing Guide**: `.github/CONTRIBUTING.md`
- **Issues**: https://github.com/umbraco/Umbraco-CMS/issues
- **Community**: https://forum.umbraco.com/
- **Releases**: https://releases.umbraco.com/
---
**This repository follows a layered architecture with strict dependency rules. The Core defines contracts, Infrastructure implements them, and Web/APIs consume them. Each layer can be understood independently, but dependencies always flow inward toward Core.**
+12 -2
View File
@@ -40,8 +40,8 @@
<!-- Package Validation -->
<PropertyGroup>
<GenerateCompatibilitySuppressionFile>false</GenerateCompatibilitySuppressionFile>
<EnablePackageValidation>false</EnablePackageValidation> <!-- TODO (V17): Set to true with version 17.0.0 once this version is released. -->
<PackageValidationBaselineVersion>16.0.0</PackageValidationBaselineVersion>
<EnablePackageValidation>true</EnablePackageValidation>
<PackageValidationBaselineVersion>18.0.0</PackageValidationBaselineVersion>
<EnableStrictModeForCompatibleFrameworksInPackage>true</EnableStrictModeForCompatibleFrameworksInPackage>
<EnableStrictModeForCompatibleTfms>true</EnableStrictModeForCompatibleTfms>
</PropertyGroup>
@@ -64,4 +64,14 @@
</_ProjectReferencesWithVersions>
</ItemGroup>
</Target>
<!-- Workaround for https://github.com/umbraco/Umbraco-CMS/issues/23018
Due to the amount of XML documentation in this solution, the OpenAPI XML documentation source generator produces
too many lines of code causing a StackOverflowException when running on IIS. For that reason we disable the analyzer.
See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/openapi-comments?view=aspnetcore-10.0#disabling-xml-documentation-support -->
<Target Name="DisableCompileTimeOpenApiXmlGenerator" BeforeTargets="CoreCompile" Condition="'$(IsPackable)' != 'false' or '$(IsTestProject)' == 'true'">
<ItemGroup>
<Analyzer Remove="@(Analyzer)" Condition="'%(Filename)' == 'Microsoft.AspNetCore.OpenApi.SourceGenerators'" />
</ItemGroup>
</Target>
</Project>
+58 -42
View File
@@ -2,81 +2,97 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<!-- Global packages (private, build-time packages for all projects) -->
<ItemGroup>
<GlobalPackageReference Include="Nerdbank.GitVersioning" Version="3.8.118" />
<GlobalPackageReference Include="Nerdbank.GitVersioning" Version="3.9.50" />
<GlobalPackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<GlobalPackageReference Include="Umbraco.Code" Version="2.4.0" />
<!-- TODO (V18): Bump Umbraco.Code to 3.0.0 stable before release of 18.0.0 -->
<GlobalPackageReference Include="Umbraco.Code" Version="3.0.0-beta" />
<GlobalPackageReference Include="Umbraco.GitVersioning.Extensions" Version="0.2.0" />
</ItemGroup>
<!-- Microsoft packages -->
<ItemGroup>
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Stores" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="10.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.7" />
<!-- When updating this version, also update templates/UmbracoExtension/Umbraco.Extension.csproj -->
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.7" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.3.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Identity.Stores" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="10.5.0" />
<PackageVersion Include="System.Linq.Async" Version="7.0.1" />
</ItemGroup>
<!-- Umbraco packages -->
<ItemGroup>
<PackageVersion Include="Umbraco.JsonSchema.Extensions" Version="0.3.0" />
<PackageVersion Include="Umbraco.JsonSchema.Extensions" Version="0.4.0" />
</ItemGroup>
<!-- Third-party packages -->
<ItemGroup>
<PackageVersion Include="Asp.Versioning.Mvc" Version="8.1.0" />
<PackageVersion Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageVersion Include="Asp.Versioning.Mvc" Version="10.0.0" />
<PackageVersion Include="Asp.Versioning.Mvc.ApiExplorer" Version="10.0.0" />
<PackageVersion Include="Dazinator.Extensions.FileProviders" Version="2.0.0" />
<PackageVersion Include="Examine" Version="3.7.1" />
<PackageVersion Include="Examine.Core" Version="3.7.1" />
<PackageVersion Include="Examine" Version="3.8.0" />
<PackageVersion Include="Examine.Core" Version="3.8.0" />
<PackageVersion Include="HtmlAgilityPack" Version="1.12.4" />
<PackageVersion Include="JsonPatch.Net" Version="3.3.0" />
<PackageVersion Include="K4os.Compression.LZ4" Version="1.3.8" />
<PackageVersion Include="MailKit" Version="4.14.0" />
<PackageVersion Include="MailKit" Version="4.16.0" />
<PackageVersion Include="Markdig" Version="1.1.3" />
<PackageVersion Include="Markdown" Version="2.2.1" />
<PackageVersion Include="MessagePack" Version="3.1.4" />
<PackageVersion Include="MessagePack" Version="3.1.7" />
<PackageVersion Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" />
<PackageVersion Include="MiniProfiler.Shared" Version="4.5.4" />
<PackageVersion Include="ncrontab" Version="3.4.0" />
<PackageVersion Include="NPoco" Version="6.1.0" />
<PackageVersion Include="NPoco.SqlServer" Version="6.1.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="7.1.0" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="7.1.0" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.1.0" />
<PackageVersion Include="Serilog" Version="4.3.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="NPoco" Version="6.2.0" />
<PackageVersion Include="NPoco.SqlServer" Version="6.2.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="7.5.0" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="7.5.0" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.5.0" />
<PackageVersion Include="Serilog" Version="4.3.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageVersion Include="Serilog.Enrichers.Process" Version="3.0.0" />
<PackageVersion Include="Serilog.Enrichers.Thread" Version="4.0.0" />
<PackageVersion Include="Serilog.Expressions" Version="5.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="9.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="10.0.0" />
<PackageVersion Include="Serilog.Formatting.Compact" Version="3.0.0" />
<PackageVersion Include="Serilog.Formatting.Compact.Reader" Version="4.0.0" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="9.0.0" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageVersion Include="Serilog.Sinks.Map" Version="2.0.0" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.11" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageVersion Include="SixLabors.ImageSharp.Web" Version="3.2.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="9.0.6" />
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.1.7" />
</ItemGroup>
<!-- Transitive pinned versions (only required because our direct dependencies have vulnerable versions of transitive dependencies) -->
<ItemGroup>
<!-- Dazinator.Extensions.FileProviders references vulnerable versions of the following: -->
<!-- TODO (V18): Remove these pinned dependencies when the Dazinator.Extensions.FileProviders dependency is removed. -->
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<!-- Markdown references vulnerable version of the following: -->
<!-- TODO (V19): Remove these pinned dependencies when the Markdown dependency is removed. -->
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<!-- Examine (via Microsoft.AspNetCore.DataProtection 8.0.4) references a vulnerable version of the following: -->
<!-- TODO: Remove this pinned dependency when Examine updates its Microsoft.AspNetCore.DataProtection reference. -->
<PackageVersion Include="System.Security.Cryptography.Xml" Version="10.0.7" />
</ItemGroup>
</Project>
+144
View File
@@ -0,0 +1,144 @@
# MCP (Model Context Protocol) Setup
This repository includes configuration for [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers, enabling AI tooling integration for Umbraco CMS development workflows.
## Overview
MCP allows AI assistants (like Claude) to interact with external tools and services. This repository configures two MCP servers:
| Server | Purpose | Package |
|--------|---------|---------|
| **umbraco-cms** | Manage Umbraco content types, documents, and media | `@umbraco-cms/mcp-dev@17` |
| **playwright** | Browser automation for testing and debugging | `@playwright/mcp@latest` |
## Quick Start
### 1. Start Umbraco Locally
Ensure your local Umbraco instance is running at `https://localhost:44339` (or update the URL in your `.env.local`).
### 2. Configure Environment Variables
Copy the example environment file and customize it:
```bash
cp .env.example .env.local
```
Edit `.env.local` with your local settings:
```env
UMBRACO_CLIENT_ID=umbraco-back-office-mcp
UMBRACO_CLIENT_SECRET=<your-client-secret>
UMBRACO_BASE_URL=https://localhost:44339
NODE_TLS_REJECT_UNAUTHORIZED=0
UMBRACO_INCLUDE_TOOL_COLLECTIONS=data-type,document-type,document,media-type,media
```
### 3. Configure the OAuth Client in Umbraco
Create an OAuth client in your Umbraco instance with:
- **Client ID**: `umbraco-back-office-mcp`
- **Client Secret**: The value you set in `.env.local`
- **Grant Type**: Client Credentials
## Environment Variables Reference
| Variable | Description | Example |
|----------|-------------|---------|
| `UMBRACO_CLIENT_ID` | OAuth client ID configured in Umbraco | `umbraco-back-office-mcp` |
| `UMBRACO_CLIENT_SECRET` | OAuth client secret (keep secure!) | `your-secure-secret` |
| `UMBRACO_BASE_URL` | URL of your local Umbraco instance | `https://localhost:44339` |
| `NODE_TLS_REJECT_UNAUTHORIZED` | Set to `0` for self-signed certificates (local dev only) | `0` |
| `UMBRACO_INCLUDE_TOOL_COLLECTIONS` | Comma-separated list of tool collections to enable | `data-type,document-type,document` |
### Tool Collections
The `UMBRACO_INCLUDE_TOOL_COLLECTIONS` variable controls which Umbraco MCP tools are available:
- `data-type` - Manage data types (property editors)
- `document-type` - Manage document types (content types)
- `document` - Manage content/documents
- `media-type` - Manage media types
- `media` - Manage media items
## Security Considerations
> **Warning**: This configuration is for **local development only**.
### Self-Signed Certificates
`NODE_TLS_REJECT_UNAUTHORIZED=0` disables SSL certificate validation. This is necessary for self-signed certificates in local development but:
- **Never use in production**
- Affects all HTTPS connections made by Node.js processes
- Consider trusting your local development certificate instead
### Client Secrets
- Never commit real secrets to source control
- The `.env.local` file is gitignored for this reason
- Use strong, unique secrets even in development
- The example value `1234567890` in `.env.example` is a placeholder only
## File Structure
```
Umbraco-CMS/
├── .mcp.json # MCP server configuration
├── .env.example # Example environment variables (committed)
├── .env.local # Your local environment variables (gitignored)
├── .claude/
│ ├── settings.json # Shared Claude AI permissions (committed)
│ └── settings.local.json # Local Claude overrides (gitignored)
├── .gitignore # Ignores .env.local and settings.local.json
└── MCP.md # This documentation (you are here)
```
## Claude AI Permissions
The `.claude/settings.json` file configures which MCP tools Claude can use automatically without prompting. This is shared across the team for consistent developer experience.
### Customizing Permissions Locally
Create `.claude/settings.local.json` to override permissions for your environment:
```json
{
"permissions": {
"allow": [
"mcp__umbraco__get-all-document-types"
]
}
}
```
## Troubleshooting
### "Connection refused" errors
- Ensure Umbraco is running at the configured `UMBRACO_BASE_URL`
- Check that the port matches your local setup
### "Unauthorized" errors
- Verify the OAuth client is configured in Umbraco
- Check that `UMBRACO_CLIENT_ID` and `UMBRACO_CLIENT_SECRET` match
- Ensure the client has appropriate permissions
### "Certificate" errors
- For local development, set `NODE_TLS_REJECT_UNAUTHORIZED=0` in `.env.local`
- Alternatively, trust your local development certificate
### MCP server not starting
- Ensure Node.js is installed (v22+ recommended, matching .nvmrc)
- Run `npx @umbraco-cms/mcp-dev@17 --help` to verify the package works
## Further Reading
- [Model Context Protocol Documentation](https://modelcontextprotocol.io/)
- [Umbraco MCP Package](https://www.npmjs.com/package/@umbraco-cms/mcp-dev)
- [Playwright MCP](https://www.npmjs.com/package/@playwright/mcp)
- [Claude Code Documentation](https://docs.anthropic.com/claude-code)
+8
View File
@@ -196,6 +196,14 @@ Copyright: 2013-2024 .NET Foundation and Contributors
---
Markdig: A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET
URL: https://github.com/xoofx/markdig
License: BSD-2-Clause license
Copyright: 2018+, Alexandre Mutel. All rights reserved.
---
Markdown: A library for parsing and compiling Markdown
URL: https://github.com/hey-red/Markdown
+127 -71
View File
@@ -45,7 +45,7 @@ parameters:
- name: integrationNonReleaseTestFilter
displayName: TestFilter used for non-release type builds
type: string
default: "--filter TestCategory!=LongRunning&TestCategory!=NonCritical"
default: "TestCategory!=LongRunning&TestCategory!=NonCritical"
- name: integrationReleaseTestFilter
displayName: TestFilter used for release type builds
type: string
@@ -53,7 +53,7 @@ parameters:
- name: nonWindowsIntegrationNonReleaseTestFilter
displayName: TestFilter used for non-release type builds on non Windows agents
type: string
default: "--filter TestCategory!=LongRunning&TestCategory!=NonCritical"
default: "TestCategory!=LongRunning&TestCategory!=NonCritical"
- name: nonWindowsIntegrationReleaseTestFilter
displayName: TestFilter used for release type builds on non Windows agents
type: string
@@ -107,9 +107,17 @@ stages:
command: build
projects: $(solution)
arguments: "--configuration $(buildConfiguration) --no-restore --property:ContinuousIntegrationBuild=true --property:GeneratePackageOnBuild=true --property:PackageOutputPath=$(Build.ArtifactStagingDirectory)/nupkg"
# Publish compiled DLLs for C# API documentation generation
# Separate artifact to avoid increasing build_output size for all builds
- task: PublishPipelineArtifact@1
displayName: Publish DocFX DLLs
condition: and(succeeded(), or(eq(variables['build.NBGV_PublicRelease'], 'True'), eq('${{ parameters.buildApiDocs }}', 'True')))
inputs:
targetPath: $(Build.SourcesDirectory)/src/Umbraco.Cms/bin/Release
artifactName: csharp-docs-dlls
- powershell: |
dotnet tool install --global CycloneDX
dotnet-CycloneDX $(solution) --output $(Build.ArtifactStagingDirectory)/bom --filename bom-dotnet.xml
dotnet-CycloneDX $(solution) --spec-version 1.5 --output $(Build.ArtifactStagingDirectory)/bom --filename bom-dotnet.xml
displayName: 'Generate Backend BOM'
- powershell: |
npm install --global @cyclonedx/cyclonedx-npm
@@ -167,6 +175,34 @@ stages:
artifact: bom-frontend
displayName: 'Publish Frontend BOM'
- job: C
displayName: Build Test Helpers Package
pool:
vmImage: "ubuntu-latest"
steps:
- checkout: self
submodules: false
lfs: false
fetchDepth: 500
- template: templates/e2e-install.yml
parameters:
nodeVersion: ${{ variables.nodeVersion }}
npm_config_cache: ${{ variables.npm_config_cache }}
- template: templates/set-npm-version.yml
parameters:
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
- bash: |
echo "##[command]Running npm pack"
mkdir $(Build.ArtifactStagingDirectory)/npm-testhelpers
npm pack --pack-destination $(Build.ArtifactStagingDirectory)/npm-testhelpers
displayName: Run npm pack
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
- task: PublishPipelineArtifact@1
displayName: Publish Test Helpers npm artifact
inputs:
targetPath: $(Build.ArtifactStagingDirectory)/npm-testhelpers
artifactName: npm-testhelpers
- stage: E2E_BOM
displayName: E2E Tests BOM Generation
dependsOn: []
@@ -200,12 +236,22 @@ stages:
variables:
umbracoMajorVersion: $[ stageDependencies.Build.A.outputs['build.NBGV_VersionMajor'] ]
jobs:
# C# API Reference
# C# API Reference - uses pre-compiled DLLs for faster generation (csproj approach caused timeouts)
- job:
displayName: Build C# API Reference
pool:
vmImage: "windows-latest"
steps:
- checkout: self
submodules: false
lfs: false
fetchDepth: 1
fetchFilter: tree:0
- task: DownloadPipelineArtifact@2
displayName: Download DocFX DLLs
inputs:
artifact: csharp-docs-dlls
path: $(Build.SourcesDirectory)/src/Umbraco.Cms/bin/Release
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
@@ -215,7 +261,7 @@ stages:
inputs:
targetType: inline
script: |
choco install docfx --version=2.59.4 -y
dotnet tool install -g docfx --version 2.78.4
if ($lastexitcode -ne 0){
throw ("Error installing DocFX")
}
@@ -409,13 +455,13 @@ stages:
projects: "tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj"
testRunTitle: Integration Tests SQLite - $(Agent.OS)
${{ if and(eq(variables['Agent.OS'],'Windows_NT'), or(variables.releaseTestFilter, parameters.forceReleaseTestFilter)) }}:
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build ${{parameters.integrationReleaseTestFilter}}'
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build'
${{ elseif eq(variables['Agent.OS'],'Windows_NT') }}:
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build ${{parameters.integrationNonReleaseTestFilter}}'
arguments: '--filter "$(testFilter) & ${{parameters.integrationNonReleaseTestFilter}}" --configuration $(buildConfiguration) --no-build'
${{ elseif or(variables.releaseTestFilter, parameters.forceReleaseTestFilter) }}:
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build ${{parameters.nonWindowsIntegrationReleaseTestFilter}}'
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build'
${{ else }}:
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build ${{parameters.nonWindowsIntegrationNonReleaseTestFilter}}'
arguments: '--filter "$(testFilter) & ${{parameters.nonWindowsIntegrationNonReleaseTestFilter}}" --configuration $(buildConfiguration) --no-build'
# Integration Tests (SQL Server)
- job:
timeoutInMinutes: 180
@@ -523,13 +569,13 @@ stages:
projects: "tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj"
testRunTitle: Integration Tests SQL Server - $(Agent.OS)
${{ if and(eq(variables['Agent.OS'],'Windows_NT'), or(variables.releaseTestFilter, parameters.forceReleaseTestFilter)) }}:
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build ${{parameters.integrationReleaseTestFilter}}'
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build'
${{ elseif eq(variables['Agent.OS'],'Windows_NT') }}:
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build ${{parameters.integrationNonReleaseTestFilter}}'
arguments: '--filter "$(testFilter) & ${{parameters.integrationNonReleaseTestFilter}}" --configuration $(buildConfiguration) --no-build'
${{ elseif or(variables.releaseTestFilter, parameters.forceReleaseTestFilter) }}:
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build ${{parameters.nonWindowsIntegrationReleaseTestFilter}}'
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build'
${{ else }}:
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build ${{parameters.nonWindowsIntegrationNonReleaseTestFilter}}'
arguments: '--filter "$(testFilter) & ${{parameters.nonWindowsIntegrationNonReleaseTestFilter}}" --configuration $(buildConfiguration) --no-build'
# Stop SQL Server
- pwsh: docker stop mssql
@@ -561,7 +607,6 @@ stages:
UMBRACO__CMS__GLOBAL__VERSIONCHECKPERIOD: 0
UMBRACO__CMS__GLOBAL__USEHTTPS: true
UMBRACO__CMS__HEALTHCHECKS__NOTIFICATION__ENABLED: false
UMBRACO__CMS__KEEPALIVE__DISABLEKEEPALIVETASK: true
UMBRACO__CMS__WEBROUTING__UMBRACOAPPLICATIONURL: https://localhost:44331/
ASPNETCORE_URLS: https://localhost:44331
jobs:
@@ -780,52 +825,56 @@ stages:
publishFeedCredentials: "MyGet - Umbraco Nightly"
${{ else }}:
publishFeedCredentials: "MyGet - Pre-releases"
# Pre-release/nightly feeds: keep the `latest` dist-tag default (no `next` split).
- job:
displayName: Push to pre-release feed (npm)
steps:
- checkout: none
- download: current
artifact: npm
- bash: |
# Check if we are on a nightly build
if [ $isNightly = "False" ]; then
echo "##[debug]Prerelease build detected"
registry="https://www.myget.org/F/umbracoprereleases/npm/"
else
echo "##[debug]Nightly build detected"
registry="https://www.myget.org/F/umbraconightly/npm/"
fi
echo "@umbraco-cms:registry=$registry" >> .npmrc
env:
isNightly: ${{parameters.isNightly}}
workingDirectory: $(Pipeline.Workspace)/npm
displayName: Add scoped registry to .npmrc
- task: npmAuthenticate@0
displayName: Authenticate with npm (MyGet)
inputs:
workingFile: "$(Pipeline.Workspace)/npm/.npmrc"
- template: templates/npm-publish.yml
parameters:
artifactName: npm
customEndpoint: "MyGet (npm) - Umbracoprereleases, MyGet (npm) - Umbraconightly"
- bash: |
# Setup temp npm project to load in defaults from the local .npmrc
npm init -y
# Find the first .tgz file in the current directory and publish it
files=( ./*.tgz )
npm publish "${files[0]}"
displayName: Push to npm (MyGet)
workingDirectory: $(Pipeline.Workspace)/npm
displayName: Push to npm (MyGet)
${{ if eq(parameters.isNightly, true) }}:
registry: https://www.myget.org/F/umbraconightly/npm/
${{ else }}:
registry: https://www.myget.org/F/umbracoprereleases/npm/
- job: PublishTestHelpersNpm
displayName: Push TestHelpers to pre-release feed (npm)
steps:
- template: templates/npm-publish.yml
parameters:
artifactName: npm-testhelpers
customEndpoint: "MyGet (npm) - Umbracoprereleases, MyGet (npm) - Umbraconightly"
displayName: Push test helpers to npm (MyGet)
${{ if eq(parameters.isNightly, true) }}:
registry: https://www.myget.org/F/umbraconightly/npm/
${{ else }}:
registry: https://www.myget.org/F/umbracoprereleases/npm/
- stage: Deploy_NuGet
displayName: NuGet release
dependsOn:
- Deploy_MyGet
- Build_Docs
condition: and(succeeded(), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.nuGetDeploy}}))
dependsOn: Deploy_MyGet
# Run only when Deploy_MyGet actually ran (succeeded or failed) — not when it was skipped due to an upstream test failure.
# Inspect Deploy_MyGet's direct result rather than succeeded()/failed(), which are transitive across the full ancestor graph.
# Approval is required every run via the WaitForApproval job below.
condition: and(in(dependencies.Deploy_MyGet.result, 'Succeeded', 'SucceededWithIssues', 'Failed'), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.nuGetDeploy}}))
jobs:
- job:
- job: WaitForApproval
displayName: Wait for manual approval
pool: server
steps:
- task: ManualValidation@0
displayName: Manual approval to push to NuGet
timeoutInMinutes: 4320 # 3 days
inputs:
notifyUsers: ''
instructions: 'Approve to push the NuGet release.'
onTimeout: 'reject'
- job: Push
displayName: Push to NuGet
dependsOn: WaitForApproval
pool:
vmImage: "windows-latest" # NuGetCommand@2 is no longer supported on Ubuntu 24.04 so we'll use windows until an alternative is available.
displayName: Push to NuGet
steps:
- checkout: none
- task: DownloadPipelineArtifact@2
@@ -843,33 +892,36 @@ stages:
- stage: Deploy_Npm
displayName: Npm release
condition: and(succeeded(), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.npmDeploy}}))
# Inspect Deploy_NuGet.result directly so a MyGet failure (which is in the transitive ancestor graph)
# doesn't cascade-skip this stage via succeeded(). Deploy_NuGet must itself have succeeded — a NuGet
# failure deliberately blocks the npm release.
condition: and(in(dependencies.Deploy_NuGet.result, 'Succeeded', 'SucceededWithIssues'), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.npmDeploy}}))
dependsOn:
- Deploy_NuGet
variables:
# `latest` for stable releases, `next` for prereleases.
npmDistTag: $[ iif(eq(stageDependencies.Build.A.outputs['build.NBGV_PrereleaseVersionNoLeadingHyphen'], ''), 'latest', 'next') ]
jobs:
- job: Publish
displayName: Push to NPM
steps:
- checkout: none
- download: current
artifact: npm
- bash: echo "@umbraco-cms:registry=https://registry.npmjs.org" >> .npmrc
workingDirectory: $(Pipeline.Workspace)/npm
displayName: Add scoped registry to .npmrc
- task: npmAuthenticate@0
displayName: Authenticate with npm
inputs:
workingFile: $(Pipeline.Workspace)/npm/.npmrc
- template: templates/npm-publish.yml
parameters:
artifactName: npm
registry: https://registry.npmjs.org/
customEndpoint: "NPM - Umbraco Backoffice"
- script: |
# Setup temp npm project to load in defaults from the local .npmrc
npm init -y
# Find the first .tgz file in the current directory and publish it
files=( ./*.tgz )
npm publish "${files[0]}"
displayName: Push to npm
workingDirectory: $(Pipeline.Workspace)/npm
displayName: Push to npm
npmTag: $(npmDistTag)
- job: PublishTestHelpers
displayName: Push Test Helpers to NPM
steps:
- template: templates/npm-publish.yml
parameters:
artifactName: npm-testhelpers
registry: https://registry.npmjs.org/
customEndpoint: "NPM - Umbraco Backoffice"
displayName: Push test helpers to npm
npmTag: $(npmDistTag)
- stage: Upload_API_Docs
pool:
@@ -879,8 +931,12 @@ stages:
displayName: Upload API Documentation
dependsOn:
- Build
- Build_Docs
- Deploy_NuGet
condition: and(succeeded(), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.uploadApiDocs}}))
# Build_Docs must have produced artifacts (we won't upload anything otherwise) and Deploy_NuGet must
# have succeeded — a NuGet failure deliberately blocks the docs upload. Direct result checks avoid
# transitive succeeded()/failed() which would cascade-skip on a MyGet failure.
condition: and(in(dependencies.Build_Docs.result, 'Succeeded', 'SucceededWithIssues'), in(dependencies.Deploy_NuGet.result, 'Succeeded', 'SucceededWithIssues'), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.uploadApiDocs}}))
jobs:
- job:
displayName: Upload C# Docs
+4 -8
View File
@@ -3,17 +3,13 @@
{
"src": [
{
"src": "../../src",
"src": "../../src/Umbraco.Cms/bin/Release",
"files": [
"**/*.csproj"
"**/Umbraco.*.dll"
],
"exclude": [
"**/obj/**",
"**/bin/**",
"**/Umbraco.Web.csproj",
"**/Umbraco.Web.UI.csproj",
"**/Umbraco.Cms.StaticAssets.csproj",
"**/JsonSchema.csproj"
"**/Umbraco.Cms.StaticAssets.dll",
"**/Umbraco.Cms.Targets.dll"
]
}
],
@@ -9,7 +9,7 @@
<meta name="generator" content="docfx {{_docfxVersion}}">
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
<link rel="icon" type="image/png" href="https://our.umbraco.com/assets/images/app-icons/favicon.png">
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.css">
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.min.css">
<link rel="stylesheet" href="{{_rel}}styles/docfx.css">
<link rel="stylesheet" href="{{_rel}}styles/main.css">
<meta property="docfx:navrel" content="{{_navRel}}">
+9 -3
View File
@@ -54,11 +54,17 @@ steps:
- pwsh: |
$sourcePath = "$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/tests/${{ parameters.testFolder }}/AdditionalSetup"
$destinationPath = "UmbracoProject"
$csharpFiles = Get-ChildItem -Path $sourcePath -Filter "*.cs"
$csharpFiles = Get-ChildItem -Path $sourcePath -Filter "*.cs" -Recurse
if ($csharpFiles) {
$csharpFiles | ForEach-Object {
Write-Host "Copying: $($_.FullName)"
Copy-Item -Path $_.FullName -Destination $destinationPath -Force
$relativePath = $_.FullName.Substring($sourcePath.Length + 1)
$targetPath = Join-Path -Path $destinationPath -ChildPath $relativePath
$targetDir = Split-Path -Path $targetPath -Parent
if (-not (Test-Path -Path $targetDir)) {
New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
}
Write-Host "Copying: $($_.FullName) -> $targetPath"
Copy-Item -Path $_.FullName -Destination $targetPath -Force
}
} else {
Write-Host "No C# files found."
+2 -2
View File
@@ -44,7 +44,7 @@ steps:
$cmsVersion = "$(Build.BuildNumber)" -replace "\+",".g"
dotnet new nugetconfig
dotnet nuget add source ./nupkg --name Local
dotnet new install Umbraco.Templates::$cmsVersion
dotnet new umbraco --name UmbracoProject --version $cmsVersion --exclude-gitignore --no-restore --no-update-check
dotnet new install Umbraco.Templates@$cmsVersion
dotnet new umbraco --name UmbracoProject --exclude-gitignore --no-restore --no-update-check
displayName: Install Template
workingDirectory: $(Agent.BuildDirectory)/app
+102 -23
View File
@@ -5,12 +5,10 @@ trigger: none
schedules:
- cron: '0 0 * * *'
displayName: Daily midnight build
displayName: Daily 0AM build (main)
branches:
include:
- v15/dev
- main
- v17/dev
parameters:
- name: skipIntegrationTests
@@ -18,16 +16,22 @@ parameters:
type: boolean
default: false
- name: differentAppSettingsAcceptanceTests
displayName: Run acceptance tests with different app settings
- name: skipDifferentAppSettingsAcceptanceTests
displayName: Skip acceptance tests with different app settings
type: boolean
default: true
default: false
- name: skipDefaultConfigAcceptanceTests
displayName: Skip tests with DefaultConfig
type: boolean
default: false
# Can we slow our tests down when running on SQLite? That way we might be able to avoid DB locks
- name: skipSqliteAcceptanceTests
displayName: Skip SQLite acceptance tests
type: boolean
default: true
variables:
nodeVersion: 20
solution: umbraco.sln
@@ -113,7 +117,7 @@ stages:
- stage: Integration
displayName: Integration Tests
dependsOn: Build
condition: ${{ eq(parameters.skipIntegrationTests, false) }}
condition: and(succeeded(), ${{ eq(parameters.skipIntegrationTests, false) }})
jobs:
# Integration Tests (SQLite)
- job:
@@ -195,31 +199,37 @@ stages:
SA_PASSWORD: UmbracoAcceptance123!
strategy:
matrix:
# We split the tests into 4 parts for each OS to reduce the time it takes to run them on the pipeline
WindowsPart1Of4:
# Windows is split into 5 parts (ManagementApi split in two to avoid memory pressure on LocalDb); Linux into 4.
WindowsPart1Of5:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are part of the Umbraco.Infrastructure namespace but not part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure) & (FullyQualifiedName!~Umbraco.Infrastructure.Service)"
WindowsPart2Of4:
WindowsPart2Of5:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure.Service)"
WindowsPart3Of4:
WindowsPart3Of5:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace.
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
WindowsPart4Of4:
WindowsPart4Of5:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are part of the ManagementApi namespace.
testFilter: "(FullyQualifiedName~ManagementApi)"
# ManagementApi, heavier sub-namespaces. Trailing dots prevent "User." from matching "UserGroup." etc.
testFilter: "FullyQualifiedName~ManagementApi & (FullyQualifiedName~ManagementApi.Element. | FullyQualifiedName~ManagementApi.User. | FullyQualifiedName~ManagementApi.Document. | FullyQualifiedName~ManagementApi.DataType. | FullyQualifiedName~ManagementApi.DocumentType. | FullyQualifiedName~ManagementApi.MediaType. | FullyQualifiedName~ManagementApi.Template.)"
WindowsPart5Of5:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# ManagementApi, remainder (complement of Part4). vstest filters do not support group
testFilter: "FullyQualifiedName~ManagementApi & FullyQualifiedName!~ManagementApi.Element. & FullyQualifiedName!~ManagementApi.User. & FullyQualifiedName!~ManagementApi.Document. & FullyQualifiedName!~ManagementApi.DataType. & FullyQualifiedName!~ManagementApi.DocumentType. & FullyQualifiedName!~ManagementApi.MediaType. & FullyQualifiedName!~ManagementApi.Template."
LinuxPart1Of4:
vmImage: "ubuntu-latest"
Tests__Database__DatabaseType: SqlServer
@@ -315,7 +325,8 @@ stages:
- stage: DefaultConfigE2E
displayName: Default Config E2E Tests
dependsOn: Build
dependsOn: [Build, Integration]
condition: in(dependencies.Build.result, 'Succeeded', 'SucceededWithIssues')
variables:
npm_config_cache: $(Pipeline.Workspace)/.npm_e2e
# Enable console logging in Release mode
@@ -334,7 +345,6 @@ stages:
UMBRACO__CMS__GLOBAL__VERSIONCHECKPERIOD: 0
UMBRACO__CMS__GLOBAL__USEHTTPS: true
UMBRACO__CMS__HEALTHCHECKS__NOTIFICATION__ENABLED: false
UMBRACO__CMS__KEEPALIVE__DISABLEKEEPALIVETASK: true
UMBRACO__CMS__WEBROUTING__UMBRACOAPPLICATIONURL: https://localhost:44331/
ASPNETCORE_URLS: https://localhost:44331
jobs:
@@ -342,7 +352,7 @@ stages:
- job:
displayName: E2E Tests (SQLite)
timeoutInMinutes: 180
condition: ${{ eq(parameters.skipDefaultConfigAcceptanceTests, false) }}
condition: ${{ and(eq(parameters.skipDefaultConfigAcceptanceTests, false), eq(parameters.skipSqliteAcceptanceTests, false)) }}
variables:
# Connection string
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=Umbraco;Mode=Memory;Cache=Shared;Foreign Keys=True;Pooling=True
@@ -443,15 +453,15 @@ stages:
vmImage: "ubuntu-latest"
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True"
WindowsPart1Of3:
testCommand: "npm run test -- --shard=1/3"
testCommand: "npm run testWindows -- --shard=1/3"
testFolder: "DefaultConfig"
vmImage: "windows-latest"
WindowsPart2Of3:
testCommand: "npm run test -- --shard=2/3"
testCommand: "npm run testWindows -- --shard=2/3"
testFolder: "DefaultConfig"
vmImage: "windows-latest"
WindowsPart3Of3:
testCommand: "npm run test -- --shard=3/3"
testCommand: "npm run testWindows -- --shard=3/3"
testFolder: "DefaultConfig"
vmImage: "windows-latest"
pool:
@@ -496,7 +506,8 @@ stages:
- stage: AdditionalConfigE2E
displayName: Additional Config E2E Tests
dependsOn: Build
dependsOn: [Build, DefaultConfigE2E]
condition: in(dependencies.Build.result, 'Succeeded', 'SucceededWithIssues')
variables:
npm_config_cache: $(Pipeline.Workspace)/.npm_e2e
ASPNETCORE_URLS: https://localhost:44331
@@ -505,7 +516,7 @@ stages:
jobs:
- job:
displayName: E2E Tests with Different App settings (SQL Server)
condition: ${{ eq(parameters.differentAppSettingsAcceptanceTests, true) }}
condition: ${{ eq(parameters.skipDifferentAppSettingsAcceptanceTests, false) }}
timeoutInMinutes: 180
variables:
SA_PASSWORD: UmbracoAcceptance123!
@@ -564,6 +575,49 @@ stages:
CONNECTIONSTRINGS__UMBRACODBDSN: Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: false
# EntityDataPicker
WindowsEntityDataPicker:
vmImage: "windows-latest"
testFolder: "EntityDataPicker"
port: ''
testCommand: "npx playwright test --project=entityDataPicker"
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: false
LinuxEntityDataPicker:
vmImage: "ubuntu-latest"
testFolder: "EntityDataPicker"
port: ''
testCommand: "npx playwright test --project=entityDataPicker"
CONNECTIONSTRINGS__UMBRACODBDSN: Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: false
# ContentSettingConfig
WindowsContentSettingsConfig:
vmImage: "windows-latest"
testFolder: "ContentSettingConfig"
port: ''
testCommand: "npx playwright test --project=contentSettingConfig"
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: false
LinuxContentSettingsConfig:
vmImage: "ubuntu-latest"
testFolder: "ContentSettingConfig"
port: ''
testCommand: "npx playwright test --project=contentSettingConfig"
CONNECTIONSTRINGS__UMBRACODBDSN: Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: false
# SMTP
LinuxSMTP:
vmImage: "ubuntu-latest"
testFolder: "SMTP"
port: ''
testCommand: "npx playwright test --project=smtp"
CONNECTIONSTRINGS__UMBRACODBDSN: Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: false
pool:
vmImage: $(vmImage)
steps:
@@ -641,6 +695,23 @@ stages:
AZUREADB2CCLIENTID: $(AZUREB2CCLIENTID)
AZUREADB2CCLIENTSECRET: $(AZUREB2CCLIENTSECRET)
# Start SMTP4dev via Docker for SMTP tests
- bash: |
echo "Starting SMTP4dev container..."
docker run -d --name smtp4dev -p 5000:80 -p 25:25 rnwood/smtp4dev
echo "Waiting for SMTP4dev to be ready..."
for i in {1..30}; do
if curl -s http://localhost:5000/api/messages > /dev/null; then
echo "SMTP4dev is ready"
break
fi
echo "Attempt $i: Waiting for SMTP4dev..."
sleep 2
done
displayName: Start SMTP4dev Docker container (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'), contains(variables['testFolder'], 'SMTP'))
# Run tests Template
- template: nightly-E2E-run-tests-template.yml
parameters:
@@ -651,6 +722,14 @@ stages:
AZUREB2CTESTUSERPASSWORD: $(AZUREB2CTESTUSERPASSWORD)
DatabaseType: ${{ variables.DatabaseType }}
# Stop SMTP4dev container
- bash: |
echo "Stopping SMTP4dev container..."
docker stop smtp4dev
docker rm smtp4dev
displayName: Stop SMTP4dev Docker container
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'), contains(variables['testFolder'], 'SMTP'))
- stage: NotifySlackBot
displayName: Notify Slack on Failure
dependsOn: DefaultConfigE2E
@@ -695,4 +774,4 @@ stages:
--data "$PAYLOAD" \
"$SLACK_WEBHOOK_URL"
env:
SLACK_WEBHOOK_URL: $(E2ESLACKWEBHOOKURL)
SLACK_WEBHOOK_URL: $(E2ESLACKWEBHOOKURL)
+2 -1
View File
@@ -9,7 +9,8 @@ schedules:
branches:
include:
- v13/dev
- v17/dev
- v16/dev
- v18/dev
- main
steps:
+3 -10
View File
@@ -6,16 +6,9 @@ steps:
versionSource: 'fromFile'
versionFilePath: src/Umbraco.Web.UI.Client/.nvmrc
- bash: |
echo "##[command]Install nbgv"
dotnet tool install --tool-path . nbgv
echo "##[command]Running nbgv get-version"
PACKAGE_VERSION=$(nbgv get-version -v NpmPackageVersion)
echo "##[command]Running npm version"
echo "##[debug]Version: $PACKAGE_VERSION"
cd src/Umbraco.Web.UI.Client
npm version $PACKAGE_VERSION --allow-same-version --no-git-tag-version
displayName: Set NPM Version
- template: set-npm-version.yml
parameters:
workingDirectory: src/Umbraco.Web.UI.Client
- task: Cache@2
displayName: Cache node_modules
+12 -13
View File
@@ -13,12 +13,12 @@ jobs:
- checkout: none
- bash: |
project_id=$(curl --no-progress-meter -H "X-Api-Key: $(DT_API_KEY)" "$(DT_API_URL)/v1/project/lookup?name=${{ parameters.projectName }}&version=${{ parameters.umbracoVersion }}" | jq -r '.uuid')
project_id=$(curl --no-progress-meter -H "X-Api-Key: $(DT_API_KEY)" "$(DT_API_URI)/api/v1/project/lookup?name=${{ parameters.projectName }}&version=${{ parameters.umbracoVersion }}" | jq -r '.uuid')
if [ "$project_id" != "null" ] && [ -n "$project_id" ]; then
echo "Project '${{ parameters.projectName }}' with version '${{ parameters.umbracoVersion }}' already exists (ID: $project_id)."
else
project_id=$(curl --no-progress-meter \
-X PUT "$(DT_API_URL)/v1/project" \
-X PUT "$(DT_API_URI)/api/v1/project" \
-H "X-Api-Key: $(DT_API_KEY)" \
-H "Content-Type: application/json" \
-d '{"name": "${{ parameters.projectName }}", "version": "${{ parameters.umbracoVersion }}", "collectionLogic": "AGGREGATE_DIRECT_CHILDREN"}' \
@@ -42,15 +42,14 @@ jobs:
artifact: ${{ project.artifact }}
displayName: Download ${{ project.artifact }} artifact
- script: |
curl --no-progress-meter --fail-with-body \
-X POST "$(DT_API_URL)/v1/bom" \
-H "X-Api-Key: $(DT_API_KEY)" \
-H "Content-Type: multipart/form-data" \
-F "autoCreate=true" \
-F "projectName=${{ parameters.projectName }}-${{ project.name }}" \
-F "projectVersion=${{ parameters.umbracoVersion }}" \
-F "parentName=${{ parameters.projectName }}" \
-F "parentVersion=${{ parameters.umbracoVersion }}" \
-F "bom=@$(Pipeline.Workspace)/${{ project.artifact }}/${{ project.bomFilePath }}"
- task: upload-bom-dtrack@1
inputs:
dtrackURI: $(DT_API_URI)
dtrackAPIKey: $(DT_API_KEY)
dtrackProjAutoCreate: true
dtrackProjName: '${{ parameters.projectName }}-${{ project.name }}'
dtrackProjVersion: ${{ parameters.umbracoVersion }}
dtrackParentProjName: ${{ parameters.projectName }}
dtrackParentProjVersion: ${{ parameters.umbracoVersion }}
bomFilePath: '$(Pipeline.Workspace)/${{ project.artifact }}/${{ project.bomFilePath }}'
displayName: Upload ${{ project.name }} BOM to Dependency Track
+5 -1
View File
@@ -29,7 +29,7 @@ steps:
"UMBRACO_USER_LOGIN=${{ parameters.PlaywrightUserEmail }}
UMBRACO_USER_PASSWORD=${{ parameters.PlaywrightPassword }}
URL=${{ parameters.ASPNETCORE_URLS }}
STORAGE_STAGE_PATH=$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/playwright/.auth/user.json
STORAGE_STATE_PATH=$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/playwright/.auth/user.json
CONSOLE_ERRORS_PATH=$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/console-errors.json" | Out-File .env
displayName: Generate .env
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
@@ -47,3 +47,7 @@ steps:
- script: npm ci --no-fund --no-audit --prefer-offline
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
displayName: Restore NPM packages
- script: npm run build
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
displayName: Build test helpers
+28
View File
@@ -0,0 +1,28 @@
parameters:
- name: artifactName # "npm" or "npm-testhelpers"
type: string
- name: registry # scoped-registry URL to publish to
type: string
- name: customEndpoint # npmAuthenticate service connection(s)
type: string
- name: displayName # label for the publish step
type: string
- name: npmTag # dist-tag to publish under
type: string
default: latest
steps:
- checkout: none
- download: current
artifact: ${{ parameters.artifactName }}
- script: npm config set @umbraco-cms:registry ${{ parameters.registry }} --location=project
displayName: Add scoped registry to .npmrc
workingDirectory: $(Pipeline.Workspace)/${{ parameters.artifactName }}
- task: npmAuthenticate@0
displayName: Authenticate with npm
inputs:
workingFile: $(Pipeline.Workspace)/${{ parameters.artifactName }}/.npmrc
customEndpoint: ${{ parameters.customEndpoint }}
- script: npm publish *.tgz --tag ${{ parameters.npmTag }}
displayName: ${{ parameters.displayName }}
workingDirectory: $(Pipeline.Workspace)/${{ parameters.artifactName }}
+15
View File
@@ -0,0 +1,15 @@
parameters:
- name: workingDirectory
type: string
steps:
- bash: |
echo "##[command]Install nbgv"
dotnet tool install --tool-path . nbgv
echo "##[command]Running nbgv get-version"
PACKAGE_VERSION=$(nbgv get-version -v NpmPackageVersion)
echo "##[command]Running npm version"
echo "##[debug]Version: $PACKAGE_VERSION"
cd ${{ parameters.workingDirectory }}
npm version $PACKAGE_VERSION --allow-same-version --no-git-tag-version
displayName: Set NPM Version
+4
View File
@@ -0,0 +1,4 @@
{
"url": "https://context7.com/umbraco/umbraco-cms",
"public_key": "pk_GTIgsrGAQiHNxCirZBDIM"
}
@@ -1,10 +1,17 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using Umbraco.Cms.Core.DeliveryApi;
namespace Umbraco.Cms.Api.Common.Accessors;
/// <summary>
/// Provides access to the <see cref="IOutputExpansionStrategy"/> for the current HTTP request context.
/// </summary>
public sealed class RequestContextOutputExpansionStrategyAccessor : RequestContextServiceAccessorBase<IOutputExpansionStrategy>, IOutputExpansionStrategyAccessor
{
/// <summary>
/// Initializes a new instance of the <see cref="RequestContextOutputExpansionStrategyAccessor"/> class.
/// </summary>
/// <param name="httpContextAccessor">The HTTP context accessor.</param>
public RequestContextOutputExpansionStrategyAccessor(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
{
@@ -1,17 +1,30 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Umbraco.Cms.Api.Common.Accessors;
/// <summary>
/// Base class for accessing request-scoped services from the current HTTP context.
/// </summary>
/// <typeparam name="T">The type of service to access.</typeparam>
public abstract class RequestContextServiceAccessorBase<T>
where T : class
{
private readonly IHttpContextAccessor _httpContextAccessor;
/// <summary>
/// Initializes a new instance of the <see cref="RequestContextServiceAccessorBase{T}"/> class.
/// </summary>
/// <param name="httpContextAccessor">The HTTP context accessor.</param>
protected RequestContextServiceAccessorBase(IHttpContextAccessor httpContextAccessor)
=> _httpContextAccessor = httpContextAccessor;
/// <summary>
/// Attempts to retrieve the service from the current HTTP context's request services.
/// </summary>
/// <param name="requestStartNodeService">When this method returns, contains the service instance if found; otherwise, <c>null</c>.</param>
/// <returns><c>true</c> if the service was found; otherwise, <c>false</c>.</returns>
public bool TryGetValue([NotNullWhen(true)] out T? requestStartNodeService)
{
requestStartNodeService = _httpContextAccessor.HttpContext?.RequestServices.GetService<T>();
@@ -1,9 +1,19 @@
namespace Umbraco.Cms.Api.Common.Attributes;
/// <summary>
/// Attribute used to map a class to a specific API for OpenAPI documentation generation.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MapToApiAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="MapToApiAttribute"/> class.
/// </summary>
/// <param name="apiName">The name of the API to map to.</param>
public MapToApiAttribute(string apiName) => ApiName = apiName;
/// <summary>
/// Gets the name of the API this class is mapped to.
/// </summary>
public string ApiName { get; }
}
@@ -1,9 +1,12 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.Builders;
/// <summary>
/// A fluent builder for creating RFC 7807 <see cref="ProblemDetails"/> responses.
/// </summary>
public class ProblemDetailsBuilder
{
private string? _title;
@@ -12,24 +15,45 @@ public class ProblemDetailsBuilder
private string? _operationStatus;
private IDictionary<string, object>? _extensions;
/// <summary>
/// Sets the title of the problem details.
/// </summary>
/// <param name="title">A short, human-readable summary of the problem type.</param>
/// <returns>The current builder instance for method chaining.</returns>
public ProblemDetailsBuilder WithTitle(string title)
{
_title = title;
return this;
}
/// <summary>
/// Sets the detail of the problem details.
/// </summary>
/// <param name="detail">A human-readable explanation specific to this occurrence of the problem.</param>
/// <returns>The current builder instance for method chaining.</returns>
public ProblemDetailsBuilder WithDetail(string detail)
{
_detail = detail;
return this;
}
/// <summary>
/// Sets the type of the problem details.
/// </summary>
/// <param name="type">A URI reference that identifies the problem type.</param>
/// <returns>The current builder instance for method chaining.</returns>
public ProblemDetailsBuilder WithType(string type)
{
_type = type;
return this;
}
/// <summary>
/// Sets the operation status from an enum value.
/// </summary>
/// <typeparam name="TEnum">The enum type representing operation statuses.</typeparam>
/// <param name="operationStatus">The operation status enum value.</param>
/// <returns>The current builder instance for method chaining.</returns>
public ProblemDetailsBuilder WithOperationStatus<TEnum>(TEnum operationStatus)
where TEnum : Enum
{
@@ -37,9 +61,20 @@ public class ProblemDetailsBuilder
return this;
}
/// <summary>
/// Adds request model validation errors to the problem details.
/// </summary>
/// <param name="errors">A dictionary of field names to error messages.</param>
/// <returns>The current builder instance for method chaining.</returns>
public ProblemDetailsBuilder WithRequestModelErrors(IDictionary<string, string[]> errors)
=> WithExtension(nameof(HttpValidationProblemDetails.Errors).ToFirstLowerInvariant(), errors);
/// <summary>
/// Adds a custom extension to the problem details.
/// </summary>
/// <param name="key">The extension key.</param>
/// <param name="value">The extension value.</param>
/// <returns>The current builder instance for method chaining.</returns>
public ProblemDetailsBuilder WithExtension(string key, object value)
{
_extensions ??= new Dictionary<string, object>();
@@ -47,6 +82,10 @@ public class ProblemDetailsBuilder
return this;
}
/// <summary>
/// Builds the <see cref="ProblemDetails"/> instance with all configured values.
/// </summary>
/// <returns>A new <see cref="ProblemDetails"/> instance.</returns>
public ProblemDetails Build()
{
var problemDetails = new ProblemDetails
+343
View File
@@ -0,0 +1,343 @@
# Umbraco.Cms.Api.Common
Shared infrastructure for Umbraco CMS REST APIs (Management and Delivery).
---
## 1. Architecture
**Type**: Class Library (NuGet Package)
**Target Framework**: .NET 10.0
**Purpose**: Common API infrastructure - OpenAPI/Swagger, JSON serialization, OpenIddict authentication, problem details
### Key Technologies
- **ASP.NET Core** - Web framework
- **Microsoft.AspNetCore.OpenApi** - OpenAPI document generation
- **Swashbuckle.AspNetCore.SwaggerUI** - Swagger UI for browsing API documentation
- **OpenIddict** - OAuth 2.0/OpenID Connect authentication
- **Asp.Versioning** - API versioning
- **System.Text.Json** - Polymorphic JSON serialization
### Dependencies
- `Umbraco.Core` - Domain models and service contracts
- `Umbraco.Web.Common` - Web functionality
### Project Structure (46 files)
```
Umbraco.Cms.Api.Common/
├── OpenApi/ # OpenAPI transformers and schema generators
│ ├── UmbracoSchemaIdGenerator.cs # Generates schema IDs (e.g., "PagedUserModel")
│ ├── UmbracoOperationIdTransformer.cs # Generates operation IDs
│ ├── SortTagsAndPathsTransformer.cs # Sorts OpenAPI tags and paths
│ ├── TagActionsByGroupNameTransformer.cs # Tags operations by controller group
│ ├── FixFileReturnTypesTransformer.cs # Fixes file return type schemas
│ ├── RequireNonNullablePropertiesSchemaTransformer.cs # Schema nullability
│ └── OpenApiRouteTemplatePipelineFilter.cs # Adds OpenAPI endpoints
├── Serialization/ # JSON type resolution
│ └── UmbracoJsonTypeInfoResolver.cs
├── Configuration/ # Options configuration
│ ├── ConfigureUmbracoOpenApiOptionsBase.cs
│ └── ConfigureOpenIddict.cs
├── DependencyInjection/ # Service registration
│ ├── UmbracoBuilderApiExtensions.cs
│ └── UmbracoBuilderAuthExtensions.cs
├── Builders/ # RFC 7807 problem details
│ └── ProblemDetailsBuilder.cs
├── ViewModels/Pagination/ # Common DTOs
└── Security/ # Auth paths and handlers
```
### Design Patterns
1. **Builder Pattern** - `ProblemDetailsBuilder` for fluent error responses
2. **Options Pattern** - All configuration via `IConfigureOptions<T>`
---
## 2. Commands
See "Quick Reference" section at bottom for common commands.
---
## 3. Key Patterns
### Schema ID Generation (OpenApi/UmbracoSchemaIdGenerator.cs)
Static utility class that generates OpenAPI schema IDs following Umbraco's naming conventions:
```csharp
// Add "Model" suffix to avoid TypeScript name clashes
if (name.EndsWith("Model") == false)
{
// because some models names clash with common classes in TypeScript (i.e. Document),
// we need to add a "Model" postfix to all models
name = $"{name}Model";
}
// Remove invalid characters to prevent OpenAPI generation errors
return Regex.Replace(name, @"[^\w]", string.Empty);
```
**Generic Type Handling**: `PagedViewModel<RelationItemViewModel>` becomes `PagedRelationItemModel`
### Polymorphic Deserialization (Serialization/UmbracoJsonTypeInfoResolver.cs:29-35)
```csharp
// IMPORTANT: do NOT return an empty enumerable here. it will cause nullability to fail on reference
// properties, because "$ref" does not mix and match well with "nullable" in OpenAPI.
if (type.IsInterface is false)
{
return new[] { type };
}
```
**Why**: Interfaces must return concrete types to avoid OpenAPI schema conflicts.
---
## 4. Testing
**Location**: No direct tests - tested via integration tests in consuming APIs
**How to test changes**:
```bash
# Run integration tests that exercise this library
dotnet test tests/Umbraco.Tests.Integration/
# Verify OpenAPI generation
# 1. Run the application: dotnet run --project src/Umbraco.Web.UI
# 2. Navigate to /umbraco/openapi/ for Swagger UI
# 3. Check schema IDs and operation IDs
# OpenAPI JSON documents available at:
# - /umbraco/openapi/management.json (Management API)
# - /umbraco/openapi/delivery.json (Delivery API)
```
**Focus areas when testing**:
- OpenAPI document generation (schema IDs, operation IDs)
- Polymorphic JSON serialization/deserialization
- OpenIddict authentication flow
- Problem details formatting
---
## 5. OpenIddict Authentication
### Key Configuration (DependencyInjection/UmbracoBuilderAuthExtensions.cs)
**Reference Tokens over JWT** (line 76-80):
```csharp
// Enable reference tokens
// - see https://documentation.openiddict.com/configuration/token-storage.html
options
.UseReferenceAccessTokens()
.UseReferenceRefreshTokens();
```
**Why**: More secure (revocable), better for load balancing, uses ASP.NET Core Data Protection.
**Token Lifetime** (line 88-91):
```csharp
// Make the access token lifetime 25% of the refresh token lifetime
options.SetAccessTokenLifetime(new TimeSpan(timeOut.Ticks / 4));
options.SetRefreshTokenLifetime(timeOut);
```
**PKCE Required** (line 59-63):
```csharp
// Enable authorization code flow with PKCE
options
.AllowAuthorizationCodeFlow()
.RequireProofKeyForCodeExchange()
.AllowRefreshTokenFlow();
```
**Endpoints**: Backoffice `/umbraco/management/api/v1/security/*`, Member `/umbraco/member/api/v1/security/*`
### Secure Cookie-Based Token Storage (v17+)
**Implementation** (DependencyInjection/HideBackOfficeTokensHandler.cs):
Back-office tokens are hidden from client-side JavaScript via HTTP-only cookies:
```csharp
private const string AccessTokenCookieKey = "__Host-umbAccessToken";
private const string RefreshTokenCookieKey = "__Host-umbRefreshToken";
// Tokens are encrypted via Data Protection and stored in cookies
SetCookie(httpContext, AccessTokenCookieKey, context.Response.AccessToken);
context.Response.AccessToken = "[redacted]"; // Client sees redacted value
```
**Key Security Features** (lines 143-165): `HttpOnly`, `IsEssential`, `Path="/"`, `Secure` (HTTPS), `__Host-` prefix
**Configuration**: `BackOfficeTokenCookieSettings.Enabled` (default: true in v17+)
**Implications**: Client-side cannot access tokens; encrypted with Data Protection; load balancing needs shared key ring; API requests need `credentials: include`
---
## 6. Common Issues & Edge Cases
### Polymorphic Deserialization Requires `$type`
**Issue**: Deserializing to an interface without `$type` discriminator fails.
**Handled in** (Json/NamedSystemTextJsonInputFormatter.cs:24-29):
```csharp
catch (NotSupportedException exception)
{
// This happens when trying to deserialize to an interface, without sending the $type as part of the request
context.ModelState.TryAddModelException(string.Empty, new InputFormatterException(exception.Message, exception));
return await InputFormatterResult.FailureAsync();
}
```
**Solution**: Clients must include `$type` property for interface types, or use concrete types.
### Schema ID Collisions with TypeScript
**Issue**: Type names like `Document` clash with TypeScript built-ins.
**Solution**: `UmbracoSchemaIdGenerator` adds "Model" suffix to all schema names.
### Generic Type Handling
**Issue**: `PagedViewModel<T>` needs flattened schema name.
**Solution**: `UmbracoSchemaIdGenerator.Generate()` flattens generic types:
- `PagedViewModel<RelationItemViewModel>` becomes `PagedRelationItemModel`
---
## 7. Extending This Library
### Adding Custom OpenAPI Transformers
OpenAPI transformers are scoped per-document. To customize a document, implement `IOpenApiDocumentTransformer`, `IOpenApiOperationTransformer`, or `IOpenApiSchemaTransformer` and register with your OpenAPI options.
For schema ID generation, use the static `UmbracoSchemaIdGenerator.Generate(Type)` method.
### Customizing Problem Details
```csharp
var problemDetails = new ProblemDetailsBuilder()
.WithTitle("Validation Failed")
.WithDetail("The request contains errors")
.WithType("ValidationError")
.WithOperationStatus(MyOperationStatus.ValidationFailed)
.WithRequestModelErrors(errors)
.Build();
return BadRequest(problemDetails);
```
---
## 8. Project-Specific Notes
### Per-Document Transformer Scoping
With Microsoft.AspNetCore.OpenApi, transformers are configured per OpenAPI document. This means custom transformers only apply to the documents they're registered with, not globally. Each API (Management, Delivery) configures its own transformers via `ConfigureUmbracoOpenApiOptionsBase` subclasses.
### Performance: Subtype Caching
**Why**: Cache discovered subtypes (UmbracoJsonTypeInfoResolver.cs:14) to avoid expensive reflection calls
### Known Limitations
1. **Polymorphic Deserialization**:
- Requires `$type` discriminator in JSON for interfaces
- Only discovers types in Umbraco namespaces
- Not all .NET types are discoverable
2. **OpenAPI Schema Generation**:
- Generic types are flattened (e.g., `PagedViewModel<T>``PagedTModel`)
- Type names may need "Model" suffix to avoid clashes
3. **OpenIddict Multi-Server**:
- Requires shared Data Protection key ring
- All servers must have synchronized clocks (NTP)
- Reference tokens require database storage
### External Dependencies
**OpenIddict**:
- OAuth 2.0 / OpenID Connect provider
- Version: See `Directory.Packages.props`
- Uses ASP.NET Core Data Protection for token encryption
**Microsoft.AspNetCore.OpenApi**:
- OpenAPI 3.1.1 document generation
- Custom transformers: `SchemaIdTransformer`, `OperationIdTransformer`, `MimeTypeDocumentTransformer`, `ServerTransformer`
**Swashbuckle.AspNetCore.SwaggerUI**:
- Swagger UI for browsing and testing API endpoints
- Accessed at `/umbraco/openapi/`
**Asp.Versioning**:
- API versioning via `ApiVersion` attribute
- API explorer integration for multi-version Swagger docs
### Configuration
**HTTPS**: `DisableTransportSecurityRequirement` for local dev only (ConfigureOpenIddict.cs:14). **Warning**: Never disable in production.
### Usage Pattern
Consuming APIs call `builder.AddUmbracoOpenApi().AddUmbracoOpenIddict()`
---
## Quick Reference
### Essential Commands
```bash
# Build project
dotnet build src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj
# Pack for NuGet
dotnet pack src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj -c Release
# Test via integration tests
dotnet test tests/Umbraco.Tests.Integration/
# Check packages
dotnet list src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj package --outdated
dotnet list src/Umbraco.Cms.Api.Common/Umbraco.Cms.Api.Common.csproj package --vulnerable
```
### Key Classes
| Class | Purpose | File |
|-------|---------|------|
| `ProblemDetailsBuilder` | Build RFC 7807 error responses | Builders/ProblemDetailsBuilder.cs |
| `UmbracoSchemaIdGenerator` | Generate OpenAPI schema IDs | OpenApi/UmbracoSchemaIdGenerator.cs |
| `UmbracoOperationIdTransformer` | Generate operation IDs | OpenApi/UmbracoOperationIdTransformer.cs |
| `UmbracoJsonTypeInfoResolver` | Polymorphic JSON serialization | Serialization/UmbracoJsonTypeInfoResolver.cs |
| `UmbracoBuilderAuthExtensions` | Configure OpenIddict | DependencyInjection/UmbracoBuilderAuthExtensions.cs |
| `HideBackOfficeTokensHandler` | Secure cookie-based token storage | DependencyInjection/HideBackOfficeTokensHandler.cs |
| `PagedViewModel<T>` | Generic pagination model | ViewModels/Pagination/PagedViewModel.cs |
### Important Files
- `Umbraco.Cms.Api.Common.csproj` - Project dependencies
- `DependencyInjection/UmbracoBuilderApiExtensions.cs` - OpenAPI registration (line 12-31)
- `DependencyInjection/UmbracoBuilderAuthExtensions.cs` - OpenIddict setup (line 20-183)
- `Security/Paths.cs` - API endpoint path constants
### Getting Help
- **Root documentation**: `/CLAUDE.md` - Repository overview
- **Core patterns**: `/src/Umbraco.Core/CLAUDE.md` - Core contracts and patterns
- **Official docs**: https://docs.umbraco.com/
- **OpenIddict docs**: https://documentation.openiddict.com/
---
**This library is the foundation for all Umbraco CMS REST APIs. Focus on OpenAPI customization, authentication configuration, and polymorphic serialization when working here.**
@@ -1,10 +1,14 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Umbraco.Cms.Api.Common.Configuration;
/// <summary>
/// Configures <see cref="ApiBehaviorOptions"/> for Umbraco APIs.
/// </summary>
public class ConfigureApiBehaviorOptions : IConfigureOptions<ApiBehaviorOptions>
{
/// <inheritdoc/>
public void Configure(ApiBehaviorOptions options) =>
// disable ProblemDetails as default result type for every non-success response (i.e. 404)
// - see https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.apibehavioroptions.suppressmapclienterrors
@@ -0,0 +1,47 @@
using System.Reflection;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Umbraco.Cms.Api.Common.OpenApi;
namespace Umbraco.Cms.Api.Common.Configuration;
/// <summary>
/// Configures the OpenAPI options for the Default API.
/// </summary>
internal class ConfigureDefaultApiOptions : ConfigureUmbracoOpenApiOptionsBase
{
/// <inheritdoc />
protected override string ApiName => DefaultApiConfiguration.ApiName;
/// <inheritdoc />
protected override string ApiTitle => "Default API";
/// <inheritdoc />
protected override string ApiVersion => "Latest";
/// <inheritdoc />
protected override string ApiDescription => "All endpoints not defined under specific APIs";
/// <inheritdoc />
protected override bool ShouldInclude(ApiDescription apiDescription)
{
// Exclude controllers with ExcludeFromDefaultOpenApiDocumentAttribute
if (apiDescription.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor
&& controllerActionDescriptor.ControllerTypeInfo.GetCustomAttribute<ExcludeFromDefaultOpenApiDocumentAttribute>() is not null)
{
return false;
}
// Include if explicitly mapped to this document
if (base.ShouldInclude(apiDescription))
{
return true;
}
// Include endpoints not explicitly assigned to another document
ApiVersionMetadata apiVersionMetadata = apiDescription.ActionDescriptor.ApiVersionMetadata;
return string.IsNullOrEmpty(apiVersionMetadata.Name);
}
}
@@ -5,12 +5,21 @@ using Umbraco.Cms.Api.Common.Json;
namespace Umbraco.Cms.Api.Common.Configuration;
/// <summary>
/// Configures <see cref="MvcOptions"/> with named JSON input and output formatters for Umbraco APIs.
/// </summary>
public class ConfigureMvcJsonOptions : IConfigureOptions<MvcOptions>
{
private readonly string _jsonOptionsName;
private readonly IOptionsMonitor<JsonOptions> _jsonOptions;
private readonly ILoggerFactory _loggerFactory;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureMvcJsonOptions"/> class.
/// </summary>
/// <param name="jsonOptionsName">The name of the JSON options configuration to use.</param>
/// <param name="jsonOptions">The JSON options monitor.</param>
/// <param name="loggerFactory">The logger factory.</param>
public ConfigureMvcJsonOptions(
string jsonOptionsName,
IOptionsMonitor<JsonOptions> jsonOptions,
@@ -21,6 +30,7 @@ public class ConfigureMvcJsonOptions : IConfigureOptions<MvcOptions>
_loggerFactory = loggerFactory;
}
/// <inheritdoc/>
public void Configure(MvcOptions options)
{
JsonOptions jsonOptions = _jsonOptions.Get(_jsonOptionsName);
@@ -4,12 +4,24 @@ using Umbraco.Cms.Core.Configuration.Models;
namespace Umbraco.Cms.Api.Common.Configuration;
/// <summary>
/// Configures OpenIddict server options for Umbraco authentication.
/// </summary>
/// <remarks>
/// Disables transport security requirement when HTTPS is not configured in global settings.
/// Warning: This should only be used in development environments.
/// </remarks>
internal sealed class ConfigureOpenIddict : IConfigureOptions<OpenIddictServerAspNetCoreOptions>
{
private readonly IOptions<GlobalSettings> _globalSettings;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureOpenIddict"/> class.
/// </summary>
/// <param name="globalSettings">The global settings options.</param>
public ConfigureOpenIddict(IOptions<GlobalSettings> globalSettings) => _globalSettings = globalSettings;
/// <inheritdoc/>
public void Configure(OpenIddictServerAspNetCoreOptions options)
=> options.DisableTransportSecurityRequirement = _globalSettings.Value.UseHttps is false;
}
@@ -0,0 +1,98 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi;
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.Configuration;
/// <summary>
/// Base class for configuring OpenAPI options for Umbraco APIs.
/// </summary>
internal abstract class ConfigureUmbracoOpenApiOptionsBase : IConfigureNamedOptions<OpenApiOptions>
{
/// <summary>
/// Gets the name/identifier of the API to configure.
/// </summary>
protected abstract string ApiName { get; }
/// <summary>
/// Gets the name/identifier of the API to configure.
/// </summary>
protected abstract string ApiTitle { get; }
/// <summary>
/// Gets the version of the API to configure.
/// </summary>
protected abstract string ApiVersion { get; }
/// <summary>
/// Gets the description of the API to configure.
/// </summary>
protected abstract string ApiDescription { get; }
/// <inheritdoc />
public void Configure(OpenApiOptions options) => Configure(Options.DefaultName, options);
/// <inheritdoc />
public void Configure(string? name, OpenApiOptions options)
{
if (name != ApiName)
{
return;
}
ConfigureOpenApi(options);
}
/// <summary>
/// Configure the OpenAPI options for the specified API.
/// </summary>
/// <param name="options">The <see cref="OpenApiOptions"/> instance to configure.</param>
protected virtual void ConfigureOpenApi(OpenApiOptions options)
{
options.AddDocumentTransformer((document, _, _) =>
{
document.Info = new OpenApiInfo
{
Title = ApiTitle,
Version = ApiVersion,
Description = ApiDescription,
};
document.Servers?.Clear();
return Task.CompletedTask;
});
options.ShouldInclude = ShouldInclude;
options.CreateSchemaReferenceId = UmbracoSchemaIdGenerator.CreateSchemaReferenceId;
options.AddOperationTransformer<UmbracoOperationIdTransformer>();
// Tag actions by group name and cleanup unused tags (caused by the tag changes)
options
.AddOperationTransformer<TagActionsByGroupNameTransformer>()
.AddDocumentTransformer<TagActionsByGroupNameTransformer>()
.AddDocumentTransformer<SortTagsAndPathsTransformer>();
}
/// <summary>
/// Determines whether the specified API description should be included in this OpenAPI document.
/// </summary>
/// <param name="apiDescription">The API description to evaluate.</param>
/// <returns><c>true</c> if the endpoint should be included; otherwise, <c>false</c>.</returns>
protected virtual bool ShouldInclude(ApiDescription apiDescription)
{
if (apiDescription.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor
&& controllerActionDescriptor.HasMapToApiAttribute(ApiName))
{
return true;
}
ApiVersionMetadata apiVersionMetadata = apiDescription.ActionDescriptor.ApiVersionMetadata;
return apiVersionMetadata.Name == ApiName;
}
}
@@ -1,65 +0,0 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.Configuration;
public class ConfigureUmbracoSwaggerGenOptions : IConfigureOptions<SwaggerGenOptions>
{
private readonly IOperationIdSelector _operationIdSelector;
private readonly ISchemaIdSelector _schemaIdSelector;
private readonly ISubTypesSelector _subTypesSelector;
public ConfigureUmbracoSwaggerGenOptions(
IOperationIdSelector operationIdSelector,
ISchemaIdSelector schemaIdSelector,
ISubTypesSelector subTypesSelector)
{
_operationIdSelector = operationIdSelector;
_schemaIdSelector = schemaIdSelector;
_subTypesSelector = subTypesSelector;
}
public void Configure(SwaggerGenOptions swaggerGenOptions)
{
swaggerGenOptions.SwaggerDoc(
DefaultApiConfiguration.ApiName,
new OpenApiInfo
{
Title = "Default API",
Version = "Latest",
Description = "All endpoints not defined under specific APIs",
});
swaggerGenOptions.CustomOperationIds(description => _operationIdSelector.OperationId(description));
swaggerGenOptions.DocInclusionPredicate((name, api) =>
{
if (api.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor
&& controllerActionDescriptor.HasMapToApiAttribute(name))
{
return true;
}
ApiVersionMetadata apiVersionMetadata = api.ActionDescriptor.GetApiVersionMetadata();
return apiVersionMetadata.Name == name
|| (string.IsNullOrEmpty(apiVersionMetadata.Name) && name == DefaultApiConfiguration.ApiName);
});
swaggerGenOptions.TagActionsBy(api => new[] { api.GroupName });
swaggerGenOptions.OrderActionsBy(ActionOrderBy);
swaggerGenOptions.SchemaFilter<EnumSchemaFilter>();
swaggerGenOptions.CustomSchemaIds(_schemaIdSelector.SchemaId);
swaggerGenOptions.SelectSubTypesUsing(_subTypesSelector.SubTypes);
swaggerGenOptions.SupportNonNullableReferenceTypes();
}
// see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#change-operation-sort-order-eg-for-ui-sorting
private static string ActionOrderBy(ApiDescription apiDesc)
=> $"{apiDesc.GroupName}_{apiDesc.ActionDescriptor.AttributeRouteInfo?.Template ?? apiDesc.ActionDescriptor.RouteValues["controller"]}_{(apiDesc.ActionDescriptor.RouteValues.TryGetValue("action", out var action) ? action : null)}_{apiDesc.HttpMethod}";
}
@@ -1,6 +1,12 @@
namespace Umbraco.Cms.Api.Common.Configuration;
/// <summary>
/// Contains default configuration values for the API.
/// </summary>
internal static class DefaultApiConfiguration
{
/// <summary>
/// The default API name used for endpoints not assigned to a specific API.
/// </summary>
public const string ApiName = "default";
}
@@ -1,7 +1,10 @@
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
using OpenIddict.Server;
using OpenIddict.Validation;
using Umbraco.Cms.Core;
@@ -13,33 +16,65 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.DependencyInjection;
/// <summary>
/// Handles secure storage of back-office authentication tokens in HTTP-only cookies.
/// </summary>
/// <remarks>
/// This handler intercepts OpenIddict token responses for the back-office client and stores
/// access tokens, refresh tokens, and PKCE codes in encrypted HTTP-only cookies. The tokens
/// are redacted from the response to prevent client-side JavaScript access.
/// </remarks>
internal sealed class HideBackOfficeTokensHandler
: IOpenIddictServerHandler<OpenIddictServerEvents.ApplyTokenResponseContext>,
IOpenIddictServerHandler<OpenIddictServerEvents.ApplyAuthorizationResponseContext>,
IOpenIddictServerHandler<OpenIddictServerEvents.ExtractTokenRequestContext>,
IOpenIddictServerHandler<OpenIddictServerEvents.ExtractRevocationRequestContext>,
IOpenIddictValidationHandler<OpenIddictValidationEvents.ProcessAuthenticationContext>,
INotificationHandler<UserLogoutSuccessNotification>
{
private const string RedactedTokenValue = "[redacted]";
private const string AccessTokenCookieKey = "__Host-umbAccessToken";
private const string RefreshTokenCookieKey = "__Host-umbRefreshToken";
private const string PkceCodeCookieKey = "__Host-umbPkceCode";
// The __Host- prefix enforces secure cookies at browser level (requires Secure, Path=/, no Domain).
// For local development over HTTP, we use a simpler prefix to avoid browser rejection.
private const string SecureCookiePrefix = "__Host-";
private readonly string _accessTokenCookieName = "umbAccessToken";
private readonly string _refreshTokenCookieName = "umbRefreshToken";
private readonly string _pkceCodeCookieName = "umbPkceCode";
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly ILogger<HideBackOfficeTokensHandler> _logger;
#pragma warning disable CS0618 // Type or member is obsolete
private readonly BackOfficeTokenCookieSettings _backOfficeTokenCookieSettings;
#pragma warning restore CS0618 // Type or member is obsolete
private readonly GlobalSettings _globalSettings;
/// <summary>
/// Initializes a new instance of the <see cref="HideBackOfficeTokensHandler"/> class.
/// </summary>
/// <param name="httpContextAccessor">The HTTP context accessor.</param>
/// <param name="dataProtectionProvider">The data protection provider for encrypting cookie values.</param>
/// <param name="logger">The logger.</param>
/// <param name="backOfficeTokenCookieSettings">The back-office token cookie settings.</param>
/// <param name="globalSettings">The global settings.</param>
public HideBackOfficeTokensHandler(
IHttpContextAccessor httpContextAccessor,
IDataProtectionProvider dataProtectionProvider,
ILogger<HideBackOfficeTokensHandler> logger,
#pragma warning disable CS0618 // Type or member is obsolete
IOptions<BackOfficeTokenCookieSettings> backOfficeTokenCookieSettings,
#pragma warning restore CS0618 // Type or member is obsolete
IOptions<GlobalSettings> globalSettings)
{
_httpContextAccessor = httpContextAccessor;
_dataProtectionProvider = dataProtectionProvider;
_logger = logger;
_backOfficeTokenCookieSettings = backOfficeTokenCookieSettings.Value;
_globalSettings = globalSettings.Value;
_accessTokenCookieName += _backOfficeTokenCookieSettings.SiteName;
_refreshTokenCookieName += _backOfficeTokenCookieSettings.SiteName;
_pkceCodeCookieName += _backOfficeTokenCookieSettings.SiteName;
}
/// <summary>
@@ -59,13 +94,13 @@ internal sealed class HideBackOfficeTokensHandler
if (context.Response.AccessToken is not null)
{
SetCookie(httpContext, AccessTokenCookieKey, context.Response.AccessToken);
SetCookie(httpContext, _accessTokenCookieName, context.Response.AccessToken);
context.Response.AccessToken = RedactedTokenValue;
}
if (context.Response.RefreshToken is not null)
{
SetCookie(httpContext, RefreshTokenCookieKey, context.Response.RefreshToken);
SetCookie(httpContext, _refreshTokenCookieName, context.Response.RefreshToken);
context.Response.RefreshToken = RedactedTokenValue;
}
@@ -87,7 +122,7 @@ internal sealed class HideBackOfficeTokensHandler
if (context.Response.Code is not null)
{
SetCookie(GetHttpContext(), PkceCodeCookieKey, context.Response.Code);
SetCookie(GetHttpContext(), _pkceCodeCookieName, context.Response.Code);
context.Response.Code = RedactedTokenValue;
}
@@ -105,14 +140,16 @@ internal sealed class HideBackOfficeTokensHandler
return ValueTask.CompletedTask;
}
HttpContext httpContext = GetHttpContext();
// Handle when the PKCE code is being exchanged for an access token.
if (context.Request.Code == RedactedTokenValue
&& TryGetCookie(PkceCodeCookieKey, out var code))
&& TryGetCookie(httpContext, _pkceCodeCookieName, out var code))
{
context.Request.Code = code;
// We won't need the PKCE cookie after this, let's remove it.
RemoveCookie(GetHttpContext(), PkceCodeCookieKey);
RemoveCookie(httpContext, _pkceCodeCookieName);
}
else
{
@@ -123,7 +160,7 @@ internal sealed class HideBackOfficeTokensHandler
// Handle when a refresh token is being exchanged for a new access token.
if (context.Request.RefreshToken == RedactedTokenValue
&& TryGetCookie(RefreshTokenCookieKey, out var refreshToken))
&& TryGetCookie(httpContext, _refreshTokenCookieName, out var refreshToken))
{
context.Request.RefreshToken = refreshToken;
}
@@ -138,6 +175,40 @@ internal sealed class HideBackOfficeTokensHandler
return ValueTask.CompletedTask;
}
/// <summary>
/// This is invoked when a token revocation request is received.
/// </summary>
public ValueTask HandleAsync(OpenIddictServerEvents.ExtractRevocationRequestContext context)
{
if (context.Request?.ClientId != Constants.OAuthClientIds.BackOffice)
{
// Only ever handle the back-office client.
return ValueTask.CompletedTask;
}
HttpContext httpContext = GetHttpContext();
// Determine which cookie to read based on the token type hint.
var cookieName = context.Request.TokenTypeHint == OpenIddictConstants.TokenTypeHints.RefreshToken
? _refreshTokenCookieName
: _accessTokenCookieName;
if (context.Request.Token == RedactedTokenValue
&& TryGetCookie(httpContext, cookieName, out var token))
{
context.Request.Token = token;
}
else
{
// If we got here, either the token was not redacted, or nothing was found in the expected cookie.
// If OpenIddict found a token, it could be an old token that is potentially still valid. For security
// reasons, we cannot accept that; at this point, we expect the tokens to be explicitly redacted.
context.Request.Token = null;
}
return ValueTask.CompletedTask;
}
/// <summary>
/// This is invoked when extracting the auth context for a client request.
/// </summary>
@@ -149,7 +220,7 @@ internal sealed class HideBackOfficeTokensHandler
return ValueTask.CompletedTask;
}
if (TryGetCookie(AccessTokenCookieKey, out var accessToken))
if (TryGetCookie(GetHttpContext(), _accessTokenCookieName, out var accessToken))
{
context.AccessToken = accessToken;
}
@@ -157,10 +228,11 @@ internal sealed class HideBackOfficeTokensHandler
return ValueTask.CompletedTask;
}
/// <inheritdoc/>
public void Handle(UserLogoutSuccessNotification notification)
{
HttpContext? context = _httpContextAccessor.HttpContext;
if (context is null)
HttpContext? httpContext = _httpContextAccessor.HttpContext;
if (httpContext is null)
{
// For some reason there is no ambient HTTP context, so we can't clean up the cookies.
// This is OK, because the tokens in the cookies have already been revoked at user sign-out,
@@ -168,23 +240,32 @@ internal sealed class HideBackOfficeTokensHandler
return;
}
context.Response.Cookies.Delete(AccessTokenCookieKey);
context.Response.Cookies.Delete(RefreshTokenCookieKey);
RemoveCookie(httpContext, _accessTokenCookieName);
RemoveCookie(httpContext, _refreshTokenCookieName);
}
private HttpContext GetHttpContext()
=> _httpContextAccessor.GetRequiredHttpContext();
private void SetCookie(HttpContext httpContext, string key, string value)
private string GetCookieKey(HttpContext httpContext, string cookieName)
=> _globalSettings.UseHttps || httpContext.Request.IsHttps
? $"{SecureCookiePrefix}{cookieName}"
: cookieName;
private void SetCookie(HttpContext httpContext, string cookieName, string value)
{
var key = GetCookieKey(httpContext, cookieName);
var cookieValue = EncryptionHelper.Encrypt(value, _dataProtectionProvider);
RemoveCookie(httpContext, key);
RemoveCookie(httpContext, cookieName);
httpContext.Response.Cookies.Append(key, cookieValue, GetCookieOptions(httpContext));
}
private void RemoveCookie(HttpContext httpContext, string key)
=> httpContext.Response.Cookies.Delete(key, GetCookieOptions(httpContext));
private void RemoveCookie(HttpContext httpContext, string cookieName)
{
var key = GetCookieKey(httpContext, cookieName);
httpContext.Response.Cookies.Delete(key, GetCookieOptions(httpContext));
}
private CookieOptions GetCookieOptions(HttpContext httpContext) =>
new()
@@ -211,12 +292,24 @@ internal sealed class HideBackOfficeTokensHandler
SameSite = ParseSameSiteMode(_backOfficeTokenCookieSettings.SameSite),
};
private bool TryGetCookie(string key, [NotNullWhen(true)] out string? value)
private bool TryGetCookie(HttpContext httpContext, string cookieName, [NotNullWhen(true)] out string? value)
{
if (GetHttpContext().Request.Cookies.TryGetValue(key, out var cookieValue))
var key = GetCookieKey(httpContext, cookieName);
if (httpContext.Request.Cookies.TryGetValue(key, out var cookieValue))
{
value = EncryptionHelper.Decrypt(cookieValue, _dataProtectionProvider);
return true;
try
{
value = EncryptionHelper.Decrypt(cookieValue, _dataProtectionProvider);
return true;
}
catch (CryptographicException ex)
{
// Decryption can fail if the data protection key ring has changed
// (e.g., after deployment, app pool recycle, or slot swap).
// Treat this as a missing cookie — the user will need to re-authenticate.
_logger.LogWarning(ex, "Failed to decrypt back-office token cookie '{CookieName}'. The user will need to re-authenticate.", cookieName);
RemoveCookie(httpContext, cookieName);
}
}
value = null;
@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -6,8 +6,18 @@ using Umbraco.Cms.Api.Common.Configuration;
namespace Umbraco.Cms.Api.Common.DependencyInjection;
/// <summary>
/// Extension methods for <see cref="IMvcBuilder"/>.
/// </summary>
public static class MvcBuilderExtensions
{
/// <summary>
/// Adds named JSON serialization options to the MVC builder.
/// </summary>
/// <param name="builder">The MVC builder.</param>
/// <param name="settingsName">The name for the JSON options configuration.</param>
/// <param name="configure">The action to configure the JSON options.</param>
/// <returns>The MVC builder for method chaining.</returns>
public static IMvcBuilder AddJsonOptions(this IMvcBuilder builder, string settingsName, Action<JsonOptions> configure)
{
builder.Services.Configure(settingsName, configure);
@@ -0,0 +1,75 @@
using Microsoft.AspNetCore.Http.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace Umbraco.Cms.Api.Common.DependencyInjection;
/// <summary>
/// Extension methods for replacing the internal Microsoft.AspNetCore.OpenApi schema service registration.
/// </summary>
internal static class OpenApiSchemaServiceExtensions
{
/// <summary>
/// The full name of the internal Microsoft type whose registration is replaced.
/// Used for a stringly-typed <see cref="ServiceDescriptor"/> lookup because the type is not publicly accessible.
/// </summary>
internal const string OpenApiSchemaServiceFullName = "Microsoft.AspNetCore.OpenApi.OpenApiSchemaService";
/// <summary>
/// Replaces the internal Microsoft <c>OpenApiSchemaService</c> registration for the specified document so that schema
/// generation uses the named <see cref="JsonOptions"/> rather than the default HTTP JSON options.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="documentName">The OpenAPI document key (matches the keyed singleton registered by <c>AddOpenApi(documentName)</c>).</param>
/// <param name="jsonOptionsName">The named <see cref="JsonOptions"/> to use during schema generation for this document.</param>
/// <returns>The same <see cref="IServiceCollection"/> for chaining.</returns>
/// <remarks>
/// Workaround for <see href="https://github.com/dotnet/aspnetcore/issues/66340">dotnet/aspnetcore#66340</see>.
/// </remarks>
public static IServiceCollection ReplaceOpenApiSchemaService(
this IServiceCollection services,
string documentName,
string jsonOptionsName)
=> services.ReplaceOpenApiSchemaService(
documentName,
sp => sp.GetRequiredService<IOptionsMonitor<JsonOptions>>().Get(jsonOptionsName));
/// <summary>
/// Replaces the internal Microsoft <c>OpenApiSchemaService</c> registration for the specified document so that schema
/// generation uses the <see cref="JsonOptions"/> instance produced by the supplied factory. Use this overload when
/// the options need to be resolved from the service provider, computed at the last moment, or built in a way that
/// doesn't fit the named-options lookup.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="documentName">The OpenAPI document key.</param>
/// <param name="jsonOptionsFactory">Factory invoked when the schema service is first resolved. Receives the resolving <see cref="IServiceProvider"/> and returns the <see cref="JsonOptions"/> to use.</param>
/// <returns>The same <see cref="IServiceCollection"/> for chaining.</returns>
/// <remarks>
/// Workaround for <see href="https://github.com/dotnet/aspnetcore/issues/66340">dotnet/aspnetcore#66340</see>.
/// </remarks>
public static IServiceCollection ReplaceOpenApiSchemaService(
this IServiceCollection services,
string documentName,
Func<IServiceProvider, JsonOptions> jsonOptionsFactory)
{
ServiceDescriptor descriptor = services.FirstOrDefault(sd =>
sd.ServiceType.FullName == OpenApiSchemaServiceFullName
&& Equals(sd.ServiceKey, documentName))
?? throw new InvalidOperationException(
$"Could not find a registration for {OpenApiSchemaServiceFullName} keyed with '{documentName}'. "
+ $"Ensure AddOpenApi(\"{documentName}\") has been called before {nameof(ReplaceOpenApiSchemaService)}, "
+ "or check whether the internal Microsoft.AspNetCore.OpenApi registration shape has changed.");
services.Remove(descriptor);
services.AddKeyedSingleton(
descriptor.ServiceType,
documentName,
(sp, key) => ActivatorUtilities.CreateInstance(
sp,
descriptor.ServiceType,
key,
Options.Create(jsonOptionsFactory(sp))));
return services;
}
}
@@ -0,0 +1,51 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Swashbuckle.AspNetCore.SwaggerUI;
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.DependencyInjection;
/// <summary>
/// Extension methods for <see cref="IServiceCollection"/> to configure OpenAPI services.
/// </summary>
public static class OpenApiServiceCollectionExtensions
{
/// <summary>
/// Adds an OpenAPI document to the OpenAPI UI document selector dropdown.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
/// <param name="documentName">The name/identifier of the OpenAPI document.</param>
/// <param name="documentTitle">The title to display in the UI dropdown. Defaults to <paramref name="documentName"/> if not specified.</param>
/// <returns>The <see cref="IServiceCollection"/> instance.</returns>
public static IServiceCollection AddOpenApiDocumentToUi(
this IServiceCollection services,
string documentName,
string? documentTitle = null)
=> services.AddOpenApiDocumentToUi(documentName, () => documentTitle);
/// <summary>
/// Adds an OpenAPI document to the OpenAPI UI document selector dropdown, resolving the title lazily so
/// callers (such as builder-pattern helpers) can defer it until SwaggerUI options are resolved.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
/// <param name="documentName">The name/identifier of the OpenAPI document.</param>
/// <param name="documentTitleFactory">Factory invoked when SwaggerUI options are resolved. Returning <c>null</c> falls back to <paramref name="documentName"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> instance.</returns>
internal static IServiceCollection AddOpenApiDocumentToUi(
this IServiceCollection services,
string documentName,
Func<string?> documentTitleFactory)
{
services.AddOptions<SwaggerUIOptions>()
.Configure<IOptions<UmbracoOpenApiOptions>>((swaggerUiOptions, openApiOptions) =>
{
var openApiRoute = openApiOptions.Value.RouteTemplate.Replace("{documentName}", documentName).EnsureStartsWith("/");
swaggerUiOptions.SwaggerEndpoint(openApiRoute, documentTitleFactory() ?? documentName);
swaggerUiOptions.ConfigObject.Urls = swaggerUiOptions.ConfigObject.Urls.OrderBy(x => x.Name);
});
return services;
}
}
@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using OpenIddict.Server;
using OpenIddict.Validation;
using Umbraco.Cms.Core;
@@ -6,12 +6,23 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.DependencyInjection;
/// <summary>
/// Handles OpenIddict request processing to skip handling for non-authentication requests.
/// </summary>
/// <remarks>
/// This handler prevents OpenIddict from processing every request to the server,
/// limiting its scope to back-office and well-known OpenID Connect endpoints.
/// </remarks>
public class ProcessRequestContextHandler
: IOpenIddictServerHandler<OpenIddictServerEvents.ProcessRequestContext>, IOpenIddictValidationHandler<OpenIddictValidationEvents.ProcessRequestContext>
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly string[] _pathsToHandle;
/// <summary>
/// Initializes a new instance of the <see cref="ProcessRequestContextHandler"/> class.
/// </summary>
/// <param name="httpContextAccessor">The HTTP context accessor.</param>
public ProcessRequestContextHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
@@ -21,6 +32,11 @@ public class ProcessRequestContextHandler
_pathsToHandle = [backOfficePathSegment, "/.well-known/openid-configuration", "/.well-known/jwks"];
}
/// <summary>
/// Handles the server process request context event.
/// </summary>
/// <param name="context">The process request context.</param>
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
public ValueTask HandleAsync(OpenIddictServerEvents.ProcessRequestContext context)
{
if (SkipOpenIddictHandlingForRequest())
@@ -31,6 +47,11 @@ public class ProcessRequestContextHandler
return ValueTask.CompletedTask;
}
/// <summary>
/// Handles the validation process request context event.
/// </summary>
/// <param name="context">The process request context.</param>
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
public ValueTask HandleAsync(OpenIddictValidationEvents.ProcessRequestContext context)
{
if (SkipOpenIddictHandlingForRequest())
@@ -1,32 +1,72 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Umbraco.Cms.Api.Common.Configuration;
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Cms.Api.Common.Serialization;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Web.Common.ApplicationBuilder;
using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
namespace Umbraco.Cms.Api.Common.DependencyInjection;
/// <summary>
/// Extension methods for <see cref="IUmbracoBuilder"/> to configure API services.
/// </summary>
public static class UmbracoBuilderApiExtensions
{
public static IUmbracoBuilder AddUmbracoApiOpenApiUI(this IUmbracoBuilder builder)
/// <summary>
/// Adds Umbraco API OpenAPI/Swagger UI services to the builder.
/// </summary>
/// <param name="builder">The Umbraco builder.</param>
internal static void AddUmbracoOpenApi(this IUmbracoBuilder builder)
{
if (builder.Services.Any(x => !x.IsKeyedService && x.ImplementationType == typeof(OperationIdSelector)))
if (builder.Services.Any(x => !x.IsKeyedService && x.ImplementationType == typeof(UmbracoJsonTypeInfoResolver)))
{
return builder;
return;
}
builder.Services.AddSwaggerGen();
builder.Services.ConfigureOptions<ConfigureUmbracoSwaggerGenOptions>();
builder.Services.AddOptions<UmbracoOpenApiOptions>()
.Configure<IHostingEnvironment, IWebHostEnvironment>((options, hostingEnv, webHostEnv) =>
{
options.Enabled = webHostEnv.IsProduction() is false;
var backOfficePath = hostingEnv.GetBackOfficePath().TrimStart(Constants.CharArrays.ForwardSlash);
options.RouteTemplate = $"{backOfficePath}/openapi/{{documentName}}.json";
options.UiRoutePrefix = $"{backOfficePath}/openapi";
});
builder.AddUmbracoOpenApiDocument<ConfigureDefaultApiOptions>(DefaultApiConfiguration.ApiName, "Default API");
builder.Services.AddSingleton<IUmbracoJsonTypeInfoResolver, UmbracoJsonTypeInfoResolver>();
builder.Services.AddSingleton<IOperationIdSelector, OperationIdSelector>();
builder.Services.AddSingleton<IOperationIdHandler, OperationIdHandler>();
builder.Services.AddSingleton<ISchemaIdSelector, SchemaIdSelector>();
builder.Services.AddSingleton<ISchemaIdHandler, SchemaIdHandler>();
builder.Services.AddSingleton<ISubTypesSelector, SubTypesSelector>();
builder.Services.AddSingleton<ISubTypesHandler, SubTypesHandler>();
builder.Services.Configure<UmbracoPipelineOptions>(options => options.AddFilter(new SwaggerRouteTemplatePipelineFilter("UmbracoApiCommon")));
builder.Services.Configure<UmbracoPipelineOptions>(options => options.AddFilter(new OpenApiRouteTemplatePipelineFilter("UmbracoApiCommon")));
}
return builder;
/// <summary>
/// Adds and configures an Umbraco OpenAPI document with shared transformers.
/// </summary>
/// <param name="builder">The Umbraco builder.</param>
/// <param name="apiName">The name/identifier of the API.</param>
/// <param name="apiTitle">The title of the API.</param>
/// <param name="jsonOptionsName">
/// Optional named <c>JsonOptions</c> to use for schema generation instead of the default HTTP JSON options.
/// When specified, replaces the internal <c>OpenApiSchemaService</c> registration for this document.
/// </param>
/// <typeparam name="TConfigureOptions">The type used to configure the OpenAPI options.</typeparam>
internal static void AddUmbracoOpenApiDocument<TConfigureOptions>(
this IUmbracoBuilder builder,
string apiName,
string apiTitle,
string? jsonOptionsName = null)
where TConfigureOptions : ConfigureUmbracoOpenApiOptionsBase
{
apiName = apiName.ToLowerInvariant();
builder.Services.AddOpenApi(apiName);
builder.Services.ConfigureOptions<TConfigureOptions>();
builder.Services.AddOpenApiDocumentToUi(apiName, apiTitle);
if (jsonOptionsName is not null)
{
builder.Services.ReplaceOpenApiSchemaService(apiName, jsonOptionsName);
}
}
}
@@ -9,14 +9,26 @@ using Umbraco.Cms.Api.Common.Security;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Infrastructure.BackgroundJobs;
using Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs.DistributedJobs;
using Umbraco.Cms.Core.Notifications;
namespace Umbraco.Cms.Api.Common.DependencyInjection;
/// <summary>
/// Extension methods for <see cref="IUmbracoBuilder"/> to configure authentication services.
/// </summary>
public static class UmbracoBuilderAuthExtensions
{
/// <summary>
/// Adds OpenIddict authentication services for Umbraco APIs.
/// </summary>
/// <param name="builder">The Umbraco builder.</param>
/// <returns>The Umbraco builder for method chaining.</returns>
/// <remarks>
/// Configures OpenIddict with authorization code flow (with PKCE), client credentials flow,
/// reference tokens, and ASP.NET Core Data Protection for token encryption.
/// </remarks>
public static IUmbracoBuilder AddUmbracoOpenIddict(this IUmbracoBuilder builder)
{
if (builder.Services.Any(x => !x.IsKeyedService && x.ImplementationType == typeof(OpenIddictCleanupJob)) is false)
@@ -133,6 +145,12 @@ public static class UmbracoBuilderAuthExtensions
.UseSingletonHandler<HideBackOfficeTokensHandler>()
.SetOrder(OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers.ExtractPostRequest<OpenIddictServerEvents.ExtractTokenRequestContext>.Descriptor.Order + 1);
});
options.AddEventHandler<OpenIddictServerEvents.ExtractRevocationRequestContext>(configuration =>
{
configuration
.UseSingletonHandler<HideBackOfficeTokensHandler>()
.SetOrder(OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers.ExtractPostRequest<OpenIddictServerEvents.ExtractRevocationRequestContext>.Descriptor.Order + 1);
});
})
// Register the OpenIddict validation components.
@@ -33,4 +33,4 @@ public static class ActionDescriptorApiCommonExtensions
return mapToApiAttributes.SingleOrDefault()?.ApiName;
}
}
}
@@ -5,9 +5,16 @@ using Umbraco.Cms.Api.Common.Configuration;
namespace Umbraco.Extensions;
/// <summary>
/// Extension methods for <see cref="MethodInfo"/> to work with API-related attributes.
/// </summary>
public static class MethodInfoApiCommonExtensions
{
/// <summary>
/// Gets the API version values from <see cref="MapToApiVersionAttribute"/> applied to the method.
/// </summary>
/// <param name="methodInfo">The method info to inspect.</param>
/// <returns>A pipe-separated string of API version values.</returns>
public static string GetMapToApiVersionAttributeValue(this MethodInfo methodInfo)
{
MapToApiVersionAttribute[] mapToApis = methodInfo.GetCustomAttributes(typeof(MapToApiVersionAttribute), inherit: true).Cast<MapToApiVersionAttribute>().ToArray();
@@ -15,6 +22,11 @@ public static class MethodInfoApiCommonExtensions
return string.Join("|", mapToApis.SelectMany(x => x.Versions));
}
/// <summary>
/// Gets the API name from <see cref="MapToApiAttribute"/> applied to the method's declaring type.
/// </summary>
/// <param name="methodInfo">The method info to inspect.</param>
/// <returns>The API name if the attribute is present; otherwise, <c>null</c>.</returns>
public static string? GetMapToApiAttributeValue(this MethodInfo methodInfo)
{
MapToApiAttribute[] mapToApis = (methodInfo.DeclaringType?.GetCustomAttributes(typeof(MapToApiAttribute), inherit: true) ?? Array.Empty<object>()).Cast<MapToApiAttribute>().ToArray();
@@ -22,6 +34,15 @@ public static class MethodInfoApiCommonExtensions
return mapToApis.SingleOrDefault()?.ApiName;
}
/// <summary>
/// Determines whether the method's declaring type has a <see cref="MapToApiAttribute"/> with the specified API name.
/// </summary>
/// <param name="methodInfo">The method info to inspect.</param>
/// <param name="apiName">The API name to check for.</param>
/// <returns>
/// <c>true</c> if the attribute is present and matches the specified API name,
/// or if the attribute is not present and the API name matches the default API name; otherwise, <c>false</c>.
/// </returns>
public static bool HasMapToApiAttribute(this MethodInfo methodInfo, string apiName)
{
var value = methodInfo.GetMapToApiAttributeValue();
@@ -1,9 +1,19 @@
namespace Umbraco.Cms.Api.Common.Filters;
namespace Umbraco.Cms.Api.Common.Filters;
/// <summary>
/// Attribute used to specify the named JSON serialization options for a controller.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class JsonOptionsNameAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="JsonOptionsNameAttribute"/> class.
/// </summary>
/// <param name="jsonOptionsName">The name of the JSON options configuration to use.</param>
public JsonOptionsNameAttribute(string jsonOptionsName) => JsonOptionsName = jsonOptionsName;
/// <summary>
/// Gets the name of the JSON options configuration.
/// </summary>
public string JsonOptionsName { get; }
}
@@ -1,10 +1,18 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using Umbraco.Cms.Api.Common.Filters;
namespace Umbraco.Cms.Api.Common.Json;
/// <summary>
/// Extension methods for <see cref="HttpContext"/> related to JSON serialization.
/// </summary>
public static class HttpContextJsonExtensions
{
/// <summary>
/// Gets the named JSON options configuration for the current endpoint.
/// </summary>
/// <param name="context">The HTTP context.</param>
/// <returns>The JSON options name if specified via <see cref="JsonOptionsNameAttribute"/>; otherwise, <c>null</c>.</returns>
public static string? CurrentJsonOptionsName(this HttpContext context)
=> context.GetEndpoint()?.Metadata.GetMetadata<JsonOptionsNameAttribute>()?.JsonOptionsName;
}
@@ -1,20 +1,31 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
namespace Umbraco.Cms.Api.Common.Json;
/// <summary>
/// A JSON input formatter that only processes requests for endpoints with matching named JSON options.
/// </summary>
internal sealed class NamedSystemTextJsonInputFormatter : SystemTextJsonInputFormatter
{
private readonly string _jsonOptionsName;
/// <summary>
/// Initializes a new instance of the <see cref="NamedSystemTextJsonInputFormatter"/> class.
/// </summary>
/// <param name="jsonOptionsName">The name of the JSON options configuration this formatter handles.</param>
/// <param name="options">The JSON options.</param>
/// <param name="logger">The logger.</param>
public NamedSystemTextJsonInputFormatter(string jsonOptionsName, JsonOptions options, ILogger<NamedSystemTextJsonInputFormatter> logger)
: base(options, logger) =>
_jsonOptionsName = jsonOptionsName;
/// <inheritdoc/>
public override bool CanRead(InputFormatterContext context)
=> context.HttpContext.CurrentJsonOptionsName() == _jsonOptionsName && base.CanRead(context);
/// <inheritdoc/>
public override async Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
{
try
@@ -1,17 +1,26 @@
using System.Text.Json;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.Formatters;
namespace Umbraco.Cms.Api.Common.Json;
/// <summary>
/// A JSON output formatter that only processes responses for endpoints with matching named JSON options.
/// </summary>
internal sealed class NamedSystemTextJsonOutputFormatter : SystemTextJsonOutputFormatter
{
private readonly string _jsonOptionsName;
/// <summary>
/// Initializes a new instance of the <see cref="NamedSystemTextJsonOutputFormatter"/> class.
/// </summary>
/// <param name="jsonOptionsName">The name of the JSON options configuration this formatter handles.</param>
/// <param name="jsonSerializerOptions">The JSON serializer options.</param>
public NamedSystemTextJsonOutputFormatter(string jsonOptionsName, JsonSerializerOptions jsonSerializerOptions) : base(jsonSerializerOptions)
{
_jsonOptionsName = jsonOptionsName;
}
/// <inheritdoc/>
public override bool CanWriteResult(OutputFormatterCanWriteContext context)
=> context.HttpContext.CurrentJsonOptionsName() == _jsonOptionsName && base.CanWriteResult(context);
}
@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection;
@@ -16,6 +16,13 @@ public sealed class EmptyCreatedAtActionResult : ActionResult
private readonly object _routeValues;
private readonly string _resourceIdentifier;
/// <summary>
/// Initializes a new instance of the <see cref="EmptyCreatedAtActionResult"/> class.
/// </summary>
/// <param name="actionName">The name of the action to generate the URL for.</param>
/// <param name="controllerName">The name of the controller to generate the URL for.</param>
/// <param name="routeValues">The route values to use for URL generation.</param>
/// <param name="resourceIdentifier">The identifier of the created resource.</param>
public EmptyCreatedAtActionResult(string actionName, string controllerName, object routeValues, string resourceIdentifier)
{
_actionName = actionName;
@@ -24,6 +31,7 @@ public sealed class EmptyCreatedAtActionResult : ActionResult
_resourceIdentifier = resourceIdentifier;
}
/// <inheritdoc/>
public override void ExecuteResult(ActionContext context)
{
ArgumentNullException.ThrowIfNull(context);
@@ -0,0 +1,177 @@
using Microsoft.AspNetCore.Http.Json;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Common.Attributes;
using Umbraco.Cms.Api.Common.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
namespace Umbraco.Cms.Api.Common.OpenApi;
/// <summary>
/// Fluent builder for configuring a custom OpenAPI document.
/// </summary>
public sealed class BackOfficeOpenApiDocumentBuilder
{
private readonly List<Action<OpenApiOptions>> _configurations = [];
private string? _title;
private string? _uiTitle;
private bool _includedInUi = true;
private Func<IServiceProvider, JsonOptions>? _httpJsonOptionsFactory;
/// <summary>
/// Initializes a new instance of the <see cref="BackOfficeOpenApiDocumentBuilder"/> class.
/// </summary>
/// <param name="documentName">The name of the OpenAPI document being configured.</param>
internal BackOfficeOpenApiDocumentBuilder(string documentName)
=> DocumentName = documentName;
/// <summary>
/// Gets the name of the OpenAPI document being configured.
/// </summary>
public string DocumentName { get; }
/// <summary>
/// Sets the document's <c>Info.Title</c>. Also used as the UI dropdown label unless overridden via
/// <see cref="WithUiTitle"/>.
/// </summary>
/// <param name="title">The title to display.</param>
/// <returns>The same builder for chaining.</returns>
public BackOfficeOpenApiDocumentBuilder WithTitle(string title)
{
_title = title;
return this;
}
/// <summary>
/// Overrides the UI dropdown label for this document.
/// </summary>
/// <param name="uiTitle">The label to display.</param>
/// <returns>The same builder for chaining.</returns>
public BackOfficeOpenApiDocumentBuilder WithUiTitle(string uiTitle)
{
_uiTitle = uiTitle;
return this;
}
/// <summary>
/// Excludes this document from the UI dropdown.
/// </summary>
/// <returns>The same builder for chaining.</returns>
public BackOfficeOpenApiDocumentBuilder ExcludeFromUi()
{
_includedInUi = false;
return this;
}
/// <summary>
/// Adds an <see cref="OpenApiOptions"/> configuration callback. Multiple calls compose.
/// </summary>
/// <param name="configure">Callback to configure the options.</param>
/// <returns>The same builder for chaining.</returns>
public BackOfficeOpenApiDocumentBuilder ConfigureOpenApiOptions(Action<OpenApiOptions> configure)
{
_configurations.Add(configure);
return this;
}
/// <summary>
/// Sets the named <see cref="JsonOptions">Microsoft.AspNetCore.Http.Json.JsonOptions</see> used when
/// generating this document's schema. Use this to match the serialization conventions of the API
/// endpoints the document describes.
/// </summary>
/// <param name="jsonOptionsName">The name of the registered HTTP <see cref="JsonOptions"/> to apply.</param>
/// <returns>The same builder for chaining.</returns>
public BackOfficeOpenApiDocumentBuilder WithJsonOptions(string jsonOptionsName)
=> WithJsonOptions(sp => sp.GetRequiredService<IOptionsMonitor<JsonOptions>>().Get(jsonOptionsName));
/// <summary>
/// Sets the <see cref="JsonOptions">Microsoft.AspNetCore.Http.Json.JsonOptions</see> used when
/// generating this document's schema. Use this to match the serialization conventions of the API
/// endpoints the document describes.
/// </summary>
/// <param name="jsonOptions">The HTTP JSON options to apply.</param>
/// <returns>The same builder for chaining.</returns>
public BackOfficeOpenApiDocumentBuilder WithJsonOptions(JsonOptions jsonOptions)
=> WithJsonOptions(_ => jsonOptions);
/// <summary>
/// Sets a factory that produces the <see cref="JsonOptions">Microsoft.AspNetCore.Http.Json.JsonOptions</see>
/// used when generating this document's schema. Use this to match the serialization conventions of the
/// API endpoints the document describes.
/// </summary>
/// <param name="jsonOptionsFactory">Factory invoked when the schema service is first resolved.</param>
/// <returns>The same builder for chaining.</returns>
public BackOfficeOpenApiDocumentBuilder WithJsonOptions(Func<IServiceProvider, JsonOptions> jsonOptionsFactory)
{
_httpJsonOptionsFactory = jsonOptionsFactory;
return this;
}
/// <summary>
/// Applies the accumulated configuration to the supplied <see cref="IUmbracoBuilder"/>'s service
/// collection. Called by <c>AddBackOfficeOpenApiDocument</c> once the user-supplied callback returns.
/// </summary>
/// <param name="builder">The Umbraco builder to register services against.</param>
internal void Build(IUmbracoBuilder builder)
{
// AddOpenApi lowercases the document name when registering its keyed services (https://github.com/dotnet/aspnetcore/blob/v10.0.9/src/OpenApi/src/Extensions/OpenApiServiceCollectionExtensions.cs#L64),
// so we must normalise here to keep AddOpenApiDocumentToUi and ReplaceOpenApiSchemaService in sync.
string lowercasedDocumentName = DocumentName.ToLowerInvariant();
builder.Services.AddOpenApi(
lowercasedDocumentName,
options =>
{
// ShouldInclude matches [MapToApi] case-insensitively to align with how documents are registered.
options.ShouldInclude = apiDescription =>
apiDescription.ActionDescriptor.EndpointMetadata
?.OfType<MapToApiAttribute>()
.Any(a => a.ApiName.Equals(DocumentName, StringComparison.OrdinalIgnoreCase))
?? false;
options.CreateSchemaReferenceId = UmbracoSchemaIdGenerator.CreateSchemaReferenceId;
if (_title is not null)
{
options.AddDocumentTransformer((document, _, _) =>
{
document.Info.Title = _title;
return Task.CompletedTask;
});
}
// Generate operation IDs using Umbraco's naming conventions.
options.AddOperationTransformer<UmbracoOperationIdTransformer>();
// Trim redundant JSON-equivalent MIME types (e.g. text/json, application/*+json, text/plain)
// that ASP.NET Core adds alongside application/json.
options.AddOperationTransformer<MimeTypesTransformer>();
// Mark non-nullable properties as required so generated SDKs reflect the C# nullability.
options.AddSchemaTransformer<RequireNonNullablePropertiesSchemaTransformer>();
// Tag actions by group name and cleanup unused tags (caused by the tag changes).
options
.AddOperationTransformer<TagActionsByGroupNameTransformer>()
.AddDocumentTransformer<TagActionsByGroupNameTransformer>()
.AddDocumentTransformer<SortTagsAndPathsTransformer>();
foreach (Action<OpenApiOptions> configure in _configurations)
{
configure(options);
}
});
if (_includedInUi)
{
builder.Services.AddOpenApiDocumentToUi(lowercasedDocumentName, _uiTitle ?? _title ?? DocumentName);
}
if (_httpJsonOptionsFactory is not null)
{
builder.Services.ReplaceOpenApiSchemaService(lowercasedDocumentName, _httpJsonOptionsFactory);
}
}
}
@@ -1,25 +0,0 @@
using System.Reflection;
using System.Runtime.Serialization;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Umbraco.Cms.Api.Common.OpenApi;
public class EnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
model.Type = "string";
model.Format = null;
model.Enum.Clear();
foreach (var name in Enum.GetNames(context.Type))
{
var actualName = context.Type.GetField(name)?.GetCustomAttribute<EnumMemberAttribute>()?.Value ?? name;
model.Enum.Add(new OpenApiString(actualName));
}
}
}
}
@@ -0,0 +1,10 @@
namespace Umbraco.Cms.Api.Common.OpenApi;
/// <summary>
/// Excludes the controller from the default OpenAPI document.
/// Use this when you have a custom OpenAPI document for your API.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class ExcludeFromDefaultOpenApiDocumentAttribute : Attribute
{
}
@@ -0,0 +1,47 @@
using System.IO.Pipelines;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
namespace Umbraco.Cms.Api.Common.OpenApi;
/// <summary>
/// Transformer to fix file return types in OpenAPI schema.
/// </summary>
/// <remarks>Can be removed once https://github.com/dotnet/aspnetcore/pull/63504 and
/// https://github.com/dotnet/aspnetcore/pull/64562 are released.</remarks>
internal class FixFileReturnTypesTransformer : IOpenApiSchemaTransformer
{
private static readonly Type[] _binaryStringTypes =
[
typeof(IFormFile),
typeof(FileResult),
typeof(Stream),
typeof(PipeReader),
];
/// <inheritdoc />
public Task TransformAsync(
OpenApiSchema schema,
OpenApiSchemaTransformerContext context,
CancellationToken cancellationToken)
{
if (_binaryStringTypes.Any(possibleBaseType => possibleBaseType.IsAssignableFrom(context.JsonTypeInfo.Type)) is false)
{
return Task.CompletedTask;
}
// Clear all properties
schema.Properties?.Clear();
schema.Required?.Clear();
// Make it an inline schema
schema.Metadata?.Remove("x-schema-id");
// Set type to string with binary format
schema.Type = JsonSchemaType.String;
schema.Format = "binary";
return Task.CompletedTask;
}
}
@@ -1,10 +0,0 @@
using Microsoft.AspNetCore.Mvc.ApiExplorer;
namespace Umbraco.Cms.Api.Common.OpenApi;
public interface IOperationIdHandler
{
bool CanHandle(ApiDescription apiDescription);
string Handle(ApiDescription apiDescription);
}
@@ -1,9 +0,0 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
namespace Umbraco.Cms.Api.Common.OpenApi;
public interface IOperationIdSelector
{
string? OperationId(ApiDescription apiDescription);
}
@@ -1,8 +0,0 @@
namespace Umbraco.Cms.Api.Common.OpenApi;
public interface ISchemaIdHandler
{
bool CanHandle(Type type);
string Handle(Type type);
}
@@ -1,6 +0,0 @@
namespace Umbraco.Cms.Api.Common.OpenApi;
public interface ISchemaIdSelector
{
string SchemaId(Type type);
}
@@ -1,8 +0,0 @@
namespace Umbraco.Cms.Api.Common.OpenApi;
public interface ISubTypesHandler
{
bool CanHandle(Type type, string documentName);
IEnumerable<Type> Handle(Type type);
}
@@ -1,6 +0,0 @@
namespace Umbraco.Cms.Api.Common.OpenApi;
public interface ISubTypesSelector
{
IEnumerable<Type> SubTypes(Type type);
}
@@ -1,48 +0,0 @@
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.OpenApi;
/// <summary>
/// This filter explicitly removes all other mime types than application/json from a named OpenAPI document when application/json is accepted.
/// </summary>
public class MimeTypeDocumentFilter : IDocumentFilter
{
private readonly string _documentName;
public MimeTypeDocumentFilter(string documentName) => _documentName = documentName;
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
if (context.DocumentName != _documentName)
{
return;
}
OpenApiOperation[] operations = swaggerDoc.Paths
.SelectMany(path => path.Value.Operations.Values)
.ToArray();
void RemoveUnwantedMimeTypes(IDictionary<string, OpenApiMediaType> content)
{
if (content.ContainsKey("application/json"))
{
content.RemoveAll(r => r.Key != "application/json");
}
}
OpenApiRequestBody[] requestBodies = operations.Select(operation => operation.RequestBody).WhereNotNull().ToArray();
foreach (OpenApiRequestBody requestBody in requestBodies)
{
RemoveUnwantedMimeTypes(requestBody.Content);
}
OpenApiResponse[] responses = operations.SelectMany(operation => operation.Responses.Values).WhereNotNull().ToArray();
foreach (OpenApiResponse response in responses)
{
RemoveUnwantedMimeTypes(response.Content);
}
}
}
@@ -0,0 +1,88 @@
using System.Net.Mime;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.OpenApi;
/// <summary>
/// Trims redundant JSON-equivalent media types from OpenAPI operations.
/// </summary>
/// <remarks>
/// <para>
/// ASP.NET Core's content negotiation populates operations with several media types that all serialize to JSON
/// (<c>text/json</c>, <c>application/*+json</c>, and <c>text/plain</c> alongside <c>application/json</c>).
/// When <c>application/json</c> is present on a response or request body, this transformer strips those
/// equivalents so OpenAPI consumers and generated SDKs aren't burdened with variants that produce identical
/// payloads. Non-JSON media types (e.g. <c>application/xml</c>, <c>application/octet-stream</c>) are preserved.
/// </para>
/// <para>
/// Request bodies additionally honour <c>[Consumes]</c>: when the attribute is present, the request content is
/// replaced entirely with the declared content types, taking precedence over the
/// JSON-equivalent stripping above.
/// </para>
/// </remarks>
internal class MimeTypesTransformer : IOpenApiOperationTransformer
{
private static readonly string[] _jsonEquivalentMimeTypes =
[
MediaTypeNames.Text.Plain,
"application/*+json",
"text/json"
];
/// <inheritdoc/>
public Task TransformAsync(
OpenApiOperation operation,
OpenApiOperationTransformerContext context,
CancellationToken cancellationToken)
{
// For request bodies, keep only the content types declared in [Consumes], or fall back to application/json.
if (operation.RequestBody?.Content is { } requestContent)
{
var explicitContentTypes = context.Description.ActionDescriptor.EndpointMetadata
.OfType<ConsumesAttribute>()
.SelectMany(p => p.ContentTypes)
.Distinct()
.ToArray();
if (explicitContentTypes.Length != 0)
{
// Replace content types entirely with what [Consumes] declares,
// preserving the schema from the existing entry.
OpenApiMediaType? existingMediaType = requestContent.Values.FirstOrDefault();
requestContent.Clear();
foreach (var contentType in explicitContentTypes)
{
requestContent[contentType] = existingMediaType ?? new OpenApiMediaType();
}
}
else
{
RemoveJsonEquivalentMimeTypes(requestContent);
}
}
// For responses, drop JSON-equivalent media types when application/json is present.
foreach (IOpenApiResponse response in (operation.Responses ?? []).Values)
{
if (response is OpenApiResponse openApiResponse)
{
RemoveJsonEquivalentMimeTypes(openApiResponse.Content);
}
}
return Task.CompletedTask;
}
private static void RemoveJsonEquivalentMimeTypes(IDictionary<string, OpenApiMediaType>? content)
{
if (content?.ContainsKey(MediaTypeNames.Application.Json) != true)
{
return;
}
content.RemoveAll(r => _jsonEquivalentMimeTypes.Contains(r.Key, StringComparer.OrdinalIgnoreCase));
}
}
@@ -0,0 +1,57 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Swashbuckle.AspNetCore.SwaggerUI;
using Umbraco.Cms.Core;
using Umbraco.Cms.Web.Common.ApplicationBuilder;
namespace Umbraco.Cms.Api.Common.OpenApi;
internal class OpenApiRouteTemplatePipelineFilter : UmbracoPipelineFilter
{
public OpenApiRouteTemplatePipelineFilter(string name)
: base(name)
{
PostPipeline = PostPipelineAction;
PreMapEndpoints = OnPreMapEndpointsAction;
}
private static void PostPipelineAction(IApplicationBuilder applicationBuilder)
{
UmbracoOpenApiOptions options = applicationBuilder.ApplicationServices
.GetRequiredService<IOptions<UmbracoOpenApiOptions>>().Value;
if (options.Enabled is false || options.DefaultUiEnabled is false)
{
return;
}
applicationBuilder.UseSwaggerUI(swaggerUiOptions => ConfigureSwaggerUi(swaggerUiOptions, options));
}
private static void OnPreMapEndpointsAction(IEndpointRouteBuilder endpoints)
{
UmbracoOpenApiOptions options = endpoints.ServiceProvider
.GetRequiredService<IOptions<UmbracoOpenApiOptions>>().Value;
if (options.Enabled is false)
{
return;
}
endpoints.MapOpenApi(options.RouteTemplate);
}
private static void ConfigureSwaggerUi(SwaggerUIOptions swaggerUiOptions, UmbracoOpenApiOptions options)
{
swaggerUiOptions.RoutePrefix = options.UiRoutePrefix;
// Add custom configuration from https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
swaggerUiOptions.ConfigObject.PersistAuthorization = true; // persists authorization data so it would not be lost on browser close/refresh
swaggerUiOptions.ConfigObject.Filter = string.Empty; // Enable the filter with an empty string as default filter.
swaggerUiOptions.OAuthClientId(Constants.OAuthClientIds.OpenApiUi);
swaggerUiOptions.OAuthUsePkce();
}
}
@@ -1,94 +0,0 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Options;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.OpenApi;
// NOTE: Left unsealed on purpose, so it is extendable.
public class OperationIdHandler : IOperationIdHandler
{
private readonly ApiVersioningOptions _apiVersioningOptions;
public OperationIdHandler(IOptions<ApiVersioningOptions> apiVersioningOptions)
=> _apiVersioningOptions = apiVersioningOptions.Value;
public bool CanHandle(ApiDescription apiDescription)
{
if (apiDescription.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor)
{
return false;
}
return CanHandle(apiDescription, controllerActionDescriptor);
}
protected virtual bool CanHandle(ApiDescription apiDescription, ControllerActionDescriptor controllerActionDescriptor)
=> controllerActionDescriptor.ControllerTypeInfo.Namespace?.StartsWith("Umbraco.Cms.Api") is true;
public virtual string Handle(ApiDescription apiDescription)
=> UmbracoOperationId(apiDescription);
/// <summary>
/// Generates a unique operation identifier for a given API following Umbraco's operation id naming conventions.
/// </summary>
protected string UmbracoOperationId(ApiDescription apiDescription)
{
if (apiDescription.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor)
{
throw new ArgumentException($"This handler operates only on {nameof(ControllerActionDescriptor)}.");
}
ApiVersion defaultVersion = _apiVersioningOptions.DefaultApiVersion;
var httpMethod = apiDescription.HttpMethod?.ToLower().ToFirstUpper() ?? "Get";
// if the route info "Name" is supplied we'll use this explicitly as the operation ID
// - usage example: [HttpGet("my-api/route}", Name = "MyCustomRoute")]
if (string.IsNullOrWhiteSpace(apiDescription.ActionDescriptor.AttributeRouteInfo?.Name) == false)
{
var explicitOperationId = apiDescription.ActionDescriptor.AttributeRouteInfo!.Name;
return explicitOperationId.InvariantStartsWith(httpMethod)
? explicitOperationId
: $"{httpMethod}{explicitOperationId}";
}
var relativePath = apiDescription.RelativePath;
if (string.IsNullOrWhiteSpace(relativePath))
{
throw new InvalidOperationException(
$"There is no relative path for controller action {apiDescription.ActionDescriptor.RouteValues["controller"]}");
}
// Remove the prefixed base path with version, e.g. /umbraco/management/api/v1/tracked-reference/{id} => tracked-reference/{id}
var unprefixedRelativePath = OperationIdRegexes
.VersionPrefixRegex()
.Replace(relativePath, string.Empty);
// Remove template placeholders, e.g. tracked-reference/{id} => tracked-reference/Id
var formattedOperationId = OperationIdRegexes
.TemplatePlaceholdersRegex()
.Replace(unprefixedRelativePath, m => $"By{m.Groups[1].Value.ToFirstUpper()}");
// Remove dashes (-) and slashes (/) and convert the following letter to uppercase with
// the word "By" in front, e.g. tracked-reference/Id => TrackedReferenceById
formattedOperationId = OperationIdRegexes
.ToCamelCaseRegex()
.Replace(formattedOperationId, m => m.Groups[1].Value.ToUpper());
// Get map to version attribute
string? version = null;
var versionAttributeValue = controllerActionDescriptor.MethodInfo.GetMapToApiVersionAttributeValue();
// We only want to add a version, if it is not the default one.
if (string.Equals(versionAttributeValue, defaultVersion.ToString()) == false)
{
version = versionAttributeValue;
}
// Return the operation ID with the formatted http method verb in front, e.g. GetTrackedReferenceById
return $"{httpMethod}{formattedOperationId.ToFirstUpper()}{version}";
}
}
@@ -1,4 +1,4 @@
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
namespace Umbraco.Cms.Api.Common.OpenApi;
@@ -1,24 +0,0 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
namespace Umbraco.Cms.Api.Common.OpenApi;
public class OperationIdSelector : IOperationIdSelector
{
private readonly IEnumerable<IOperationIdHandler> _operationIdHandlers;
[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 15.")]
public OperationIdSelector()
: this(Enumerable.Empty<IOperationIdHandler>())
{
}
public OperationIdSelector(IEnumerable<IOperationIdHandler> operationIdHandlers)
=> _operationIdHandlers = operationIdHandlers;
public virtual string? OperationId(ApiDescription apiDescription)
{
IOperationIdHandler? handler = _operationIdHandlers.FirstOrDefault(h => h.CanHandle(apiDescription));
return handler?.Handle(apiDescription);
}
}
@@ -1,25 +0,0 @@
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Umbraco.Cms.Api.Common.OpenApi;
/// <summary>
/// This filter explicitly removes all security schemes from a named OpenAPI document.
/// </summary>
public class RemoveSecuritySchemesDocumentFilter : IDocumentFilter
{
private readonly string _documentName;
public RemoveSecuritySchemesDocumentFilter(string documentName)
=> _documentName = documentName;
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
if (context.DocumentName != _documentName)
{
return;
}
swaggerDoc.Components.SecuritySchemes.Clear();
}
}
@@ -0,0 +1,48 @@
using System.Reflection;
using System.Text.Json.Serialization.Metadata;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
namespace Umbraco.Cms.Api.Common.OpenApi;
/// <summary>
/// Ensures that all non-nullable properties are marked as required in the OpenAPI schema.
/// </summary>
/// <remarks>By default, only properties marked with the required keyword will actually show as required.
/// Non-nullable reference types were not taken into account.</remarks>
internal class RequireNonNullablePropertiesSchemaTransformer : IOpenApiSchemaTransformer
{
/// <inheritdoc />
public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext context, CancellationToken cancellationToken)
{
IEnumerable<string> additionalRequiredProps = schema.Properties?
.Where(p => schema.Required?.Contains(p.Key) != true) // If it's already required, skip
.Where(x => IsRequiredProperty(schema, context.JsonTypeInfo, x.Key))
.Select(x => x.Key)
?? [];
schema.Required ??= new HashSet<string>();
foreach (var propKey in additionalRequiredProps)
{
schema.Required.Add(propKey);
}
return Task.CompletedTask;
}
private static bool IsRequiredProperty(OpenApiSchema schema, JsonTypeInfo jsonTypeInfo, string propertyName)
{
if (jsonTypeInfo.Properties.FirstOrDefault(p => p.Name == propertyName) is { } property)
{
return property.IsGetNullable is false;
}
// If we can't find the property in the type (e.g. discriminator '$type'), use the schema type information.
if (schema.Properties?.TryGetValue(propertyName, out IOpenApiSchema? schemaProperty) is true
&& schemaProperty?.Type is { } propertyType)
{
return propertyType.HasFlag(JsonSchemaType.Null) is false;
}
return false;
}
}
@@ -1,51 +0,0 @@
using System.Text.RegularExpressions;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.OpenApi;
// NOTE: Left unsealed on purpose, so it is extendable.
public class SchemaIdHandler : ISchemaIdHandler
{
public virtual bool CanHandle(Type type)
=> type.Namespace?.StartsWith("Umbraco.Cms") is true;
public virtual string Handle(Type type)
=> UmbracoSchemaId(type);
/// <summary>
/// Generates a sanitized and consistent schema identifier for a given type following Umbraco's schema id naming conventions.
/// </summary>
protected string UmbracoSchemaId(Type type)
{
var name = SanitizedTypeName(type);
name = HandleGenerics(name, type);
if (name.EndsWith("Model") == false)
{
// because some models names clash with common classes in TypeScript (i.e. Document),
// we need to add a "Model" postfix to all models
name = $"{name}Model";
}
// make absolutely sure we don't pass any invalid named by removing all non-word chars
return Regex.Replace(name, @"[^\w]", string.Empty);
}
private string SanitizedTypeName(Type t) => t.Name
// first grab the "non-generic" part of any generic type name (i.e. "PagedViewModel`1" becomes "PagedViewModel")
.Split('`').First()
// then remove the "ViewModel" postfix from type names
.TrimEnd("ViewModel");
private string HandleGenerics(string name, Type type)
{
if (!type.IsGenericType)
{
return name;
}
// use attribute custom name or append the generic type names, ultimately turning i.e. "PagedViewModel<RelationItemViewModel>" into "PagedRelationItem"
return $"{name}{string.Join(string.Empty, type.GenericTypeArguments.Select(SanitizedTypeName))}";
}
}
@@ -1,15 +0,0 @@
namespace Umbraco.Cms.Api.Common.OpenApi;
public class SchemaIdSelector : ISchemaIdSelector
{
private readonly IEnumerable<ISchemaIdHandler> _schemaIdHandlers;
public SchemaIdSelector(IEnumerable<ISchemaIdHandler> schemaIdHandlers)
=> _schemaIdHandlers = schemaIdHandlers;
public virtual string SchemaId(Type type)
{
ISchemaIdHandler? handler = _schemaIdHandlers.FirstOrDefault(h => h.CanHandle(type));
return handler?.Handle(type) ?? type.Name;
}
}
@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
namespace Umbraco.Cms.Api.Common.OpenApi;
/// <summary>
/// Transforms the OpenAPI document to sort tags and paths alphabetically.
/// </summary>
internal class SortTagsAndPathsTransformer : IOpenApiDocumentTransformer
{
/// <summary>
/// Transforms the specified OpenAPI document to sort its tags and paths alphabetically.
/// </summary>
/// <param name="document">The <see cref="OpenApiDocument"/> to modify.</param>
/// <param name="context">The <see cref="OpenApiDocumentTransformerContext"/> associated with the <paramref name="document"/>.</param>
/// <param name="cancellationToken">The cancellation token to use.</param>
/// <returns>The task object representing the asynchronous operation.</returns>
public Task TransformAsync(
OpenApiDocument document,
OpenApiDocumentTransformerContext context,
CancellationToken cancellationToken)
{
document.Tags = new SortedSet<OpenApiTag>(
document.Tags ?? Enumerable.Empty<OpenApiTag>(),
Comparer<OpenApiTag>.Create((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal)));
var sortedPaths = new OpenApiPaths();
foreach (KeyValuePair<string, IOpenApiPathItem> keyValuePair in document.Paths
.OrderBy(x => x.Value.Operations?.Values
.SelectMany(op => op.Tags ?? Enumerable.Empty<OpenApiTagReference>())
.OrderBy(t => t.Name)
.FirstOrDefault()?
.Name)
.ThenBy(x => x.Key))
{
sortedPaths.Add(keyValuePair.Key, keyValuePair.Value);
}
document.Paths = sortedPaths;
return Task.CompletedTask;
}
}
@@ -1,20 +0,0 @@
using Umbraco.Cms.Api.Common.Serialization;
namespace Umbraco.Cms.Api.Common.OpenApi;
public class SubTypesHandler : ISubTypesHandler
{
private readonly IUmbracoJsonTypeInfoResolver _umbracoJsonTypeInfoResolver;
public SubTypesHandler(IUmbracoJsonTypeInfoResolver umbracoJsonTypeInfoResolver)
=> _umbracoJsonTypeInfoResolver = umbracoJsonTypeInfoResolver;
protected virtual bool CanHandle(Type type)
=> type.Namespace?.StartsWith("Umbraco.Cms") is true;
public virtual bool CanHandle(Type type, string documentName)
=> CanHandle(type);
public virtual IEnumerable<Type> Handle(Type type)
=> _umbracoJsonTypeInfoResolver.FindSubTypes(type);
}
@@ -1,57 +0,0 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Common.Serialization;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.OpenApi;
public class SubTypesSelector : ISubTypesSelector
{
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IEnumerable<ISubTypesHandler> _subTypeHandlers;
private readonly IUmbracoJsonTypeInfoResolver _umbracoJsonTypeInfoResolver;
public SubTypesSelector(
IHostingEnvironment hostingEnvironment,
IHttpContextAccessor httpContextAccessor,
IEnumerable<ISubTypesHandler> subTypeHandlers,
IUmbracoJsonTypeInfoResolver umbracoJsonTypeInfoResolver)
{
_hostingEnvironment = hostingEnvironment;
_httpContextAccessor = httpContextAccessor;
_subTypeHandlers = subTypeHandlers;
_umbracoJsonTypeInfoResolver = umbracoJsonTypeInfoResolver;
}
public IEnumerable<Type> SubTypes(Type type)
{
var backOfficePath = _hostingEnvironment.GetBackOfficePath();
var swaggerPath = $"{backOfficePath}/swagger";
if (_httpContextAccessor.HttpContext?.Request.Path.StartsWithSegments(swaggerPath) ?? false)
{
// Split the path into segments
var segments = _httpContextAccessor.HttpContext.Request.Path.Value!
.Substring(swaggerPath.Length)
.TrimStart(Constants.CharArrays.ForwardSlash)
.Split(Constants.CharArrays.ForwardSlash);
// Extract the document name from the path
var documentName = segments[0];
// Find the first handler that can handle the type / document name combination
ISubTypesHandler? handler = _subTypeHandlers.FirstOrDefault(h => h.CanHandle(type, documentName));
if (handler != null)
{
return handler.Handle(type);
}
}
// Default implementation to maintain backwards compatibility
return _umbracoJsonTypeInfoResolver.FindSubTypes(type);
}
}

Some files were not shown because too many files have changed in this diff Show More