User-collection-table didn´t format and if you have da backoffice the time is still Am/pm
Co-authored-by: Lucas Bach Bisgaard <lucas.bisgaard@kraftvaerk.com>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
Fix detail data request manager failing as soon as the number of items requested hits the UmbItemDataApiGetRequestController batch limit (40)
Co-authored-by: Paul Woodland <paul.woodland@pwnewmedia.com>
* feat(media): add umb-thumbnail and configurable checkerboard background
Adds `umb-thumbnail` as the recommended alias of `umb-imaging-thumbnail`
(the original tag stays registered for backwards compatibility), and makes
the checkerboard background opt-out via the `--umb-thumbnail-background` CSS
custom property plus an `img` part for full styling control. Also fixes an
action-event listener leak in the thumbnail element, and adds a Storybook
story, an MDX guide, and component tests.
Closes#23177
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(media): address PR review on umb-thumbnail
- Rephrase the imaging-thumbnail JSDoc to a neutral alias statement instead of
a "prefer" wording that read like an undeclared deprecation.
- Guard the thumbnail tests so a renamed private field fails loudly rather than
producing vacuous assertions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(media): make umb-thumbnail canonical, deprecate umb-imaging-thumbnail
Invert the inheritance so the implementation lives on `UmbThumbnailElement`
(`umb-thumbnail`) and `UmbImagingThumbnailElement` (`umb-imaging-thumbnail`)
is the thin subclass. Removing the old tag is now just deleting one file.
The deprecated subclass emits a one-time `UmbDeprecation` warning (a
module-level guard avoids per-instance console spam) and carries a
`@deprecated` JSDoc, scheduled for removal in Umbraco 19.
Migrate the four internal consumers to `umb-thumbnail` so the deprecation
warning targets external code only, not our own.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(media): trim deprecated-alias thumbnail tests to a registration guard
The img part, checkerboard default and --umb-thumbnail-background override are
covered by thumbnail.element.test.ts and inherited from UmbThumbnailElement, so
re-asserting them on the umb-imaging-thumbnail subclass only tested inheritance.
Keep a single backwards-compat guard that the deprecated alias stays registered
and on the inheritance chain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(media): rename canonical thumbnail to umb-media-thumbnail; alias keeps @deprecated, no runtime warning
Per review (Niels): the forward-looking name is `umb-media-thumbnail`
(`UmbMediaThumbnailElement`), leaving room for non-media thumbnails later. The
implementation, CSS custom property (`--umb-media-thumbnail-background`), story,
guide and internal consumers all use the new name.
`umb-imaging-thumbnail` stays registered as a thin alias and keeps its
`@deprecated` JSDoc (IDE signal) but no longer emits a runtime UmbDeprecation
warning — both tags fly for now. Docs and comments lead with umb-media-thumbnail.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(core): annotate deprecation warnings with caller origin, suppress core noise in production
Deprecation warnings now state where the call most likely came from — Umbraco
core, an /App_Plugins package, or other custom code — by classifying the call
stack (first frame not under /umbraco/backoffice/ is the caller). This answers
the Codegarden feedback that you can't tell whose code triggered a warning.
In production builds, core-origin warnings are suppressed (a consumer can't act
on Umbraco's own code); package/external/unknown origins are always shown. The
production signal is the client build, not the server runtime mode — the latter
is unreliable since Umbraco Cloud defaults to BackofficeDevelopment. The new
umbIsProductionBuild() reads Vite's import.meta.env.PROD (substituted to true in
the shipped core bundle) and falls back to false outside a Vite build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(core): cleaner deprecation output and drop the throw for stack capture
Read new Error().stack directly instead of throwing and catching — the stack is
populated on construction. Annotate the warning with the resolved origin on its
own line rather than a bracketed prefix, and rely on the browser's native
expandable stack on console.warn for the full clickable trace instead of
printing one ourselves.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(core): trim inline comments in deprecation utils
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(core): address PR review on deprecation origin
- Clarify umbIsProductionBuild docs: in Vite dev import.meta.env is defined
(PROD false); the guard is for non-Vite contexts (tsc pass, web-test-runner).
- Strip query/fragment from parsed frame URLs so the external-origin label
can't carry ?/# noise.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Guard against cache poisoning from concurrency
* Resolve code review comments relating to tests.
* Avoid unnecessary second invalidation of memory cache generatio.
* Tighten the cache-generation guard.
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
* Display appropriate content type name in compositions dialog localised texts.
* Fix composition dialog translation typos and link references to the matching workspace
- fr: "sililaire" -> "similaire"
- it: "utlizzato" -> "utilizzato"
- es: remove duplicated "no puede no puede"
The reference list now builds its workspace edit href from the modal's
entityType instead of hardcoding document-type, so links resolve correctly
when the dialog is used for Media Types and Member Types.
* Integrate interaction memories into entity data picker
* Skip resetting unchanged data source API
Add an early-return guard in setDataSourceApi to avoid re-setting the same UmbPickerDataSource instance. Prevents rebuilding the modal token/route (which would close and reopen an open picker modal) on every re-render by only updating when the API actually changes.
* Add UmbEntityInputInteractionMemoryManager + implement across current inputs with memory
* clean up comment
* Block RTE: Implement unsupported block rendering
* Fixes `.ProseMirror-selectednode` focus ring
* Markup tidy-up
* Adds test for `umb-unsupported-rte-block`
* Block RTE: Reflect unsupported state as a host attribute
Replaces @state() + toggleAttribute() with @property({ reflect: true })
so Lit manages the 'unsupported' attribute sync during the update cycle,
avoiding constructor-time attribute access flagged by the linter.
Also removes the now-inert uui-text/uui-font classes from the block
wrapper div (backing styles were removed with UmbTextStyles).
* Adds JSDoc comment to `unsupported` property
* Block RTE: Extract #observeBlockViewProps() to reduce constructor size
Moves the block-view-props observer setup out of the constructor into a
dedicated #observeBlockViewProps() method, following the same pattern as
#observeData(). Reduces constructor from 123 to 64 lines (threshold: 70).
The `loaded`-signal test (added in #23167) built its host with
`UmbControllerHostElementMixin(HTMLElement)`, mirroring the older
`UmbBaseExtensionInitializer` tests. But `UmbExtensionInitializerBase`
requires a full `UmbElement` host, so the test failed `tsc` (TS2345)
under the root tsconfig. The product build excludes `*.test.ts`, so it
slipped through CI but breaks `npm run compile`/the editor.
Use `UmbElementMixin(HTMLElement)`, matching what production callers pass
(app/backoffice/preview elements are all UmbElements).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reconciles app.element.ts with #23020 (parallelized public extensions).
Kept the boot gate (await the app-entry-point initializer before routing)
and restored a blocking inline `await registerPublicExtensions()` instead
of the parallelized deferred form — a marginally slower but more robust
boot, identical to the release/17.5.0 fix (no empty-first-pass timing
reliance). extension-initializer-base.ts, the unit test, the acceptance
test and playwright config merge cleanly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* map settings to become a key-value-object
* implement type safety for block label ufm values
* added TODOs
* support variant value in Block Workspace Label
* External login: wait for app-entry-points before the login provider decision
The backoffice boot stopped waiting for app-entry-point extensions to settle
before deciding which auth provider to use (regression introduced in #22522).
On a slow connection an externally registered authProvider (e.g. Umbraco ID)
is not registered yet when the login screen renders, so the user is dropped on
the local login instead of being redirected to the external provider.
- extension-initializer-base: `loaded` re-arms to `undefined` while a pass is in
flight and resolves to `true` unconditionally (including zero extensions), so
`.asPromise()` gates correctly and never hangs on a default install (which has
no app-entry-points) — the reason the await was removed in the first place.
- app.element: restore the awaited boot gate before routing.
Tests:
- Unit test for the `loaded` signal contract (zero extensions resolves; a late,
slow extension is awaited).
- Playwright acceptance test that deploys an app-entry-point registering an
authProvider after a delay and asserts it is offered on the login screen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(backoffice): guard the loaded-gate timing for permission loading
Add a test asserting the collection initializer's `loaded` does not open the
gate (`#loadedGuard` awaits it via `.asPromise()`, fronting private-extension
and user-permission loading) until the initially-registered extensions have
instantiated. Addresses the #22522 "user permissions resolved too late" concern
in writing; user-permission condition resolution itself lives in
UmbBaseExtensionInitializer (covered by base-extension-initializer.race.test.ts)
and is untouched by this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(backoffice): harden loaded signal + narrow acceptance test glob (review)
Address PR review feedback:
- extension-initializer-base: only the latest processing pass settles `loaded`
(monotonic pass id), so a slow earlier pass can't unblock waiters early when
the async observer overlaps passes; and use `Promise.allSettled` so a throwing
`instantiateExtension` can't leave `loaded` stuck at `undefined` (hanging the
boot gate) — failures are logged rather than swallowed.
- playwright.config: narrow the project glob to `**/*.spec.ts` so Playwright
doesn't try to load the App_Plugins `entry-point.js` ESM fixture as a test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Adds UFM Member Name component
This is to support the standalone Member Picker values.
* fix(ufm): clear stale value on empty member picker; validate UDI-extracted GUIDs
* test(ufm): add umbMemberName parsing tests to marked-ufm.test.ts
Address PR review feedback:
- extension-initializer-base: only the latest processing pass settles `loaded`
(monotonic pass id), so a slow earlier pass can't unblock waiters early when
the async observer overlaps passes; and use `Promise.allSettled` so a throwing
`instantiateExtension` can't leave `loaded` stuck at `undefined` (hanging the
boot gate) — failures are logged rather than swallowed.
- playwright.config: narrow the project glob to `**/*.spec.ts` so Playwright
doesn't try to load the App_Plugins `entry-point.js` ESM fixture as a test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a test asserting the collection initializer's `loaded` does not open the
gate (`#loadedGuard` awaits it via `.asPromise()`, fronting private-extension
and user-permission loading) until the initially-registered extensions have
instantiated. Addresses the #22522 "user permissions resolved too late" concern
in writing; user-permission condition resolution itself lives in
UmbBaseExtensionInitializer (covered by base-extension-initializer.race.test.ts)
and is untouched by this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The backoffice boot stopped waiting for app-entry-point extensions to settle
before deciding which auth provider to use (regression introduced in #22522).
On a slow connection an externally registered authProvider (e.g. Umbraco ID)
is not registered yet when the login screen renders, so the user is dropped on
the local login instead of being redirected to the external provider.
- extension-initializer-base: `loaded` re-arms to `undefined` while a pass is in
flight and resolves to `true` unconditionally (including zero extensions), so
`.asPromise()` gates correctly and never hangs on a default install (which has
no app-entry-points) — the reason the await was removed in the first place.
- app.element: restore the awaited boot gate before routing.
Tests:
- Unit test for the `loaded` signal contract (zero extensions resolves; a late,
slow extension is awaited).
- Playwright acceptance test that deploys an app-entry-point registering an
authProvider after a delay and asserts it is offered on the login screen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 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>
* 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>
* 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>
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>
* 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.
* 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>
* Prevent empty domain cache during concurrent initialization.
* Addressed code review comments and added further comment to the code.
* Use Lock object.
* 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.
* 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>
* 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.
* Surface a package migration exception as a boot failure, avoiding being stuck in an upgrading state.
* Addressed code review feedback.
* Fix failing integration tests.
* 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
* 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>
* Prevent empty domain cache during concurrent initialization.
* Addressed code review comments and added further comment to the code.
* Use Lock object.
* 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>
* 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.
* 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
* 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).
* 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>
* 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.
* 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>
* 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>
* 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>
* 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>
* 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>
* 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.
`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>
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>
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>
* 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>
* 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>
* 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>
* 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>
* 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>
* Use direct imports in core manifests
* Extract theme aliases into constants file
---------
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
* 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).
* 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>
* 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>
* Use direct imports in core manifests
* Extract theme aliases into constants file
---------
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
* 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>
* Support anchor fragments that are included in the data attribute but missing in the href when migrating local links.
* Addressed code review feedback.
* Support anchor fragments that are included in the data attribute but missing in the href when migrating local links.
* Addressed code review feedback.
* 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>
* 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>
* 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>
* 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>
* 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>
* 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
* 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>
* 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>
* 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.
* 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>
* 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>
* 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>
* 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>
* 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.
* 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.
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.
* 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.
* 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>
* 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>
* 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>
* 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>
* 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>
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.
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.
* 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)
* 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>
* 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>
* 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
* 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
* 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)
* 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>
* 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)
* 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
* 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>
* 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>
* 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!
* 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.
* 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.
* 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.
* 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>
* 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
* 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>
* 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>
* 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>
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>
* 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>
* 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>
* 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.
* 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>
* 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>
* 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>
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>
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>
* 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>
* 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>
* 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
* 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
* 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>
* 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>
* 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>
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>
* 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>
* 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>
* 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)
* 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>
* 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.
* 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
* 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
* 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)
* 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)
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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.
* 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
* 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>
* Align GUID-via-UDI and integer locallink sources in migration to consistent type attribute casing.
* Handle Pascal cased type attributes from local links.
* 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>
* 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>
* 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>
* 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>
* 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>
* Ensure that DocumentUrlService and DocumentUrlAliasService will respect read-only, subscriber databases.
* Fixed breaking change in constructor.
* Clarified comment.
* Use pattern matching in SkipDatabaseWrites() check.
* Ensure that DocumentUrlService and DocumentUrlAliasService will respect read-only, subscriber databases.
* Fixed breaking change in constructor.
* Clarified comment.
* Use pattern matching in SkipDatabaseWrites() check.
* 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>
* 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>
* 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>
* 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>
* 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.
* 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.
* 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.
* 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>
* 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.
* 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>
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.
* 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
* 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.
* 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>
* Removed line clamp for data type picker
* Removed line clamp on additional labels
---------
Co-authored-by: Engiber Lozada <89547469+engijlr@users.noreply.github.com>
* 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>
* 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
* Emit relation saved and deleted notification when automatic relations are added and removed during content updates.
* Addressed code review feedback.
* 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>
* 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>
* Fix branch authorization from requiring recycle bin permission.
* Use named parameters.
---------
Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
* 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>
* Allow packages and hosted services to set an ambient backoffice identity via AsyncLocal for scenarios where no HttpContext is available.
* Addressed code review feedback.
* 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>
* Use GeneratedRegex instead of generating at runtime
* Add unit tests to verify refactored code.
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
* 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>
* 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.
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>
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>
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>
* 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
* 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>
* 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>
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>
* 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>
* 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>
* Eliminate closure, fix naming & formatting of exceptions
* Added unit tests around the changed code.
---------
Co-authored-by: Andy Butland <abutland73@gmail.com>
* Use configured or detected application URL as request URL fallback in background tasks when constructing absolute URLs.
* Addresed code review feedback.
* 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>
* 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>
* 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.
* 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>
* 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>
* 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>
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>
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>
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>
* 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>
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>
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>
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>
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>
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>
* 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>
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>
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>
* 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>
* 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
* 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>
* 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.
* 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>
* 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>
* 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
* 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
* 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>
MediaBreadthFirstSeedCount was initialized with StaticDocumentBreadthFirstSeedCount
instead of StaticMediaBreadthFirstSeedCount, mismatching its [DefaultValue] attribute.
* 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>
* 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>
* 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
* 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>
* 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>
* 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
* 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>
* 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>
* 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
* 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.
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
* 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>
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
* 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>
* 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>
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>
* Update Microsoft.Extensions.Caching.Hybrid to latest minor, and other Microsoft dependencies to latest patch.
* Align test and local web project dependency versions.
* 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>
* 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>
* 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
* 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>
Close readline before starting dev server
Close the readline interface before launching the Vite dev server so Ctrl+C can properly terminate the process.
* 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
* 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>
* 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.
* 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
* 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
* 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
* 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.
* 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>
* 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>
* 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
* 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>
* 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
* 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
* 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>
* 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
* 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>
* 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>
* 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
* 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>
* 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>
* 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.
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.
* 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>
* 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>
* 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>
* 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>
* 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>
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:
| 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:
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.
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.
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:
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` |
| `### 🚀 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 |
| `### 🐛 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.
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):
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:
| **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}]
[1–2 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]
[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.
"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.",
{"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)"}
"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"}
"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)"}
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)
- [ ] 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.")]
publicvoidDoThing(stringname)
=>DoThing(name,extraParam:null);
publicvoidDoThing(stringname,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
publicinterfaceIMyService
{
voidExistingMethod();
// New method with default implementation
voidNewMethod(stringparam)
=>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."
- **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 |
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." |
| **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`
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:
- **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)
@@ -198,7 +198,7 @@ Use the format: `Area: Description (closes #IssueID)`
- Describe the change and its impact
- Be specific, not vague (describe "a golden retriever" not just "a dog")
**Issue Linking**: Add `(closes #IssueID)` to auto-close linked issues on merge.
**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
@@ -227,9 +227,11 @@ Project ownership is distributed across teams. Check individual project director
1.**Layered Architecture with Dependency Inversion**
- Core defines contracts (interfaces)
- Infrastructure implements contracts
- 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
@@ -419,64 +421,27 @@ APIs use `Asp.Versioning.Mvc`:
The backoffice (`Umbraco.Web.UI.Client`) is published to npm as **`@umbraco-cms/backoffice`** with a plugin architecture:
When a PR changes Management API controllers or models, the `OpenApi.json` file in the Management API project must be updated:
#### Architecture Overview
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`
- **Multi-workspace structure**: Subprojects in `src/libs/*`, `src/packages/*`, `src/external/*`
- **Export model**: All exports defined in root `package.json` → `./exports` field
- **Importmap-driven runtime**: Dependencies provided at runtime via importmap (single source of truth)
- **Build-time types**: TypeScript types come from npm peerDependencies
- **Plugin model**: Developers create plugins that import from `@umbraco-cms/backoffice/*` exports
**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.
#### Dependency Hoisting Strategy
### Backoffice npm Package
When building for npm (`npm pack`), the `cleanse-pkg.js` script hoists subproject dependencies to root `peerDependencies` with intelligent version range conversion:
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".
**Version Range Logic** (uses `semver` package):
### SQL Server 2100-parameter limit
1. **Pre-release (0.x.y)**: Convert to explicit range
- Input: `^0.85.0` or `0.85.0`
- Output: `>=0.85.0 <1.0.0`
- Rationale: Pre-release caret only allows patch updates, explicit range allows minor upgrades within 0.x.x
- Example: Plugin can use `@hey-api/openapi-ts@0.91.1` while backoffice uses `0.85.0`
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.
2. **Stable with caret (^X.Y.Z where X ≥ 1)**: Keep as-is
- Input: `^3.3.1`
- Output: `^3.3.1` (unchanged)
- Rationale: Caret already implements correct semantics for stable versions
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.
3. **Stable exact versions (X.Y.Z where X ≥ 1)**: Add caret
- Input: `3.16.0`
- Output: `^3.16.0`
- Rationale: Normalizes to conventional semver format
#### Key Dependencies
**Runtime via importmap** (types available from peerDependencies):
- Uses `semver.minVersion()` for robust version range parsing
- Generates single source of truth for importmap versions
Full guidance, safe patterns and decision rule: see `/src/Umbraco.Infrastructure/CLAUDE.md` → "Avoiding the SQL Server 2100-parameter limit".
### Known Limitations
@@ -486,6 +451,104 @@ Plugin developers should:
---
## 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.
**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
@@ -507,6 +570,16 @@ dotnet format
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 |
@@ -534,6 +607,8 @@ For detailed information about individual projects, see their CLAUDE.md files:
**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.
@@ -13,6 +13,11 @@ public class ConfigureBackOfficeSecurityStampValidatorOptions : IConfigureOption
privatereadonlySecuritySettings_securitySettings;
privatereadonlyTimeProvider_timeProvider;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureBackOfficeSecurityStampValidatorOptions"/> class with the specified security settings and time provider.
/// </summary>
/// <param name="securitySettings">The <see cref="IOptions{SecuritySettings}"/> used to access security-related configuration options.</param>
/// <param name="timeProvider">The <see cref="TimeProvider"/> used for time-based operations.</param>
/// Initializes a new instance of the <see cref="ConfigureUmbracoManagementApiSwaggerGenOptions"/> class.
/// </summary>
/// <param name="umbracoJsonTypeInfoResolver">An instance of <see cref="IUmbracoJsonTypeInfoResolver"/> used to resolve JSON type information for Umbraco.</param>
/// Serves as a base controller for managing collections of content items, providing shared functionality for handling content collections and their variants.
/// Serves as the base controller for content management operations in the Umbraco CMS API, providing shared functionality for content-related controllers.
/// Retrieves a paginated list of all available cultures, including their English and localized names.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="skip">The number of cultures to skip before starting to collect the result set.</param>
/// <param name="take">The maximum number of cultures to return.</param>
/// <returns>A task representing the asynchronous operation. The task result contains a <see cref="PagedViewModel{CultureReponseModel}"/> with the paginated cultures.</returns>
/// Retrieves the configuration settings for data types, including whether data types can be changed and the identifiers for document and media list views.
/// </summary>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>An <see cref="IActionResult"/> containing a <see cref="DatatypeConfigurationResponseModel"/> with the data type configuration settings.</returns>
/// Initializes a new instance of the <see cref="CopyDataTypeController"/> class.
/// </summary>
/// <param name="dataTypeService">An instance of <see cref="IDataTypeService"/> used to manage data types.</param>
/// <param name="backOfficeSecurityAccessor">An instance of <see cref="IBackOfficeSecurityAccessor"/> used to access back office security information.</param>
/// Creates a new data type using the configuration provided in the request model.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="createDataTypeRequestModel">The model containing the configuration details for the new data type.</param>
/// <returns>
/// An <see cref="IActionResult"/> that represents the result of the create operation. Returns <c>201 Created</c> on success, or an appropriate error response on failure.
/// Initializes a new instance of the <see cref="Umbraco.Cms.Api.Management.Controllers.DataType.Filter.FilterDataTypeFilterController"/> class, responsible for filtering data types.
/// </summary>
/// <param name="dataTypeService">The <see cref="IDataTypeService"/> used to manage data types.</param>
/// <param name="mapper">The <see cref="IUmbracoMapper"/> used for mapping entities.</param>
/// Retrieves a paginated and filtered list of data types based on the specified criteria.
/// </summary>
/// <param name="cancellationToken">A token to observe while waiting for the task to complete.</param>
/// <param name="skip">The number of items to skip before starting to collect the result set (used for pagination).</param>
/// <param name="take">The maximum number of items to return (used for pagination).</param>
/// <param name="name">An optional filter to match data type names.</param>
/// <param name="editorUiAlias">An optional filter to match the editor UI alias.</param>
/// <param name="editorAlias">An optional filter to match the editor alias.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains an <see cref="IActionResult"/> with a paged collection of filtered data types.</returns>
@@ -17,6 +25,14 @@ public class ByKeyDataTypeFolderController : DataTypeFolderControllerBase
{
}
/// <summary>
/// Retrieves a data type folder by its unique identifier.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="id">The unique identifier (GUID) of the data type folder to retrieve.</param>
/// <returns>
/// An <see cref="IActionResult"/> containing a <see cref="FolderResponseModel"/> with the folder data if found; otherwise, a <see cref="ProblemDetails"/> with status 404 if not found.
/// Initializes a new instance of the <see cref="CreateDataTypeFolderController"/> class, responsible for handling requests related to creating data type folders.
/// </summary>
/// <param name="backOfficeSecurityAccessor">Provides access to back office security features for authorization and authentication.</param>
/// <param name="dataTypeContainerService">Service used to manage data type containers (folders) within the system.</param>
@@ -17,6 +20,14 @@ public class IsUsedDataTypeController : DataTypeControllerBase
_dataTypeUsageService=dataTypeUsageService;
}
/// <summary>
/// Determines whether the data type specified by the given <paramref name="id"/> is currently used in any content, media, or member types.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="id">The unique identifier of the data type to check for usage.</param>
/// <returns>
/// An <see cref="IActionResult"/> containing a boolean value: <c>true</c> if the data type is used; <c>false</c> otherwise. Returns <see cref="StatusCodes.Status404NotFound"/> if the data type does not exist.
/// Initializes a new instance of the <see cref="ItemDatatypeItemController"/> class, which manages item-level operations for data types in the Umbraco CMS Management API.
/// </summary>
/// <param name="dataTypeService">Service used to manage and retrieve data type information.</param>
/// <param name="mapper">The Umbraco mapper used for mapping between domain and API models.</param>
@@ -23,6 +32,14 @@ public class SearchDataTypeItemController : DatatypeItemControllerBase
_mapper=mapper;
}
/// <summary>
/// Searches for data type items matching the specified query, with support for pagination.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="query">The search query used to filter data type items.</param>
/// <param name="skip">The number of items to skip before starting to collect the result set (used for pagination).</param>
/// <param name="take">The maximum number of items to return in the result set (used for pagination).</param>
/// <returns>A task representing the asynchronous operation. The task result contains an <see cref="IActionResult"/> with a <see cref="PagedModel{DataTypeItemResponseModel}"/> containing the search results.</returns>
/// Initializes a new instance of the <see cref="ReferencedByDataTypeController"/> class, which handles API requests related to data types referenced by other entities.
/// </summary>
/// <param name="dataTypeService">Service used to manage and retrieve data type information.</param>
/// <param name="relationTypePresentationFactory">Factory for creating presentation models for relation types.</param>
@@ -22,8 +30,15 @@ public class ReferencedByDataTypeController : DataTypeControllerBase
}
/// <summary>
/// Gets a paged list of references for the current data type, so you can see where it is being used.
/// Gets a paged list of entities that reference the specified data type, allowing you to see where it is being used.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="id">The unique identifier of the data type to find references for.</param>
/// <param name="skip">The number of items to skip before starting to collect the result set (used for paging).</param>
/// <param name="take">The maximum number of items to return (used for paging).</param>
/// <returns>
/// A task representing the asynchronous operation. The result contains an <see cref="ActionResult{T}"/> with a <see cref="PagedViewModel{IReferenceResponseModel}"/> listing entities that reference the specified data type.
/// Initializes a new instance of the <see cref="AncestorsDataTypeTreeController"/> class, which provides API endpoints for retrieving ancestor data types in the tree structure.
/// </summary>
/// <param name="entityService">Service used for entity operations within the API.</param>
/// <param name="dataTypeService">Service used for data type management and retrieval.</param>
[Obsolete("Please use the constructor taking all parameters. Scheduled for removal in Umbraco 18.")]
/// Initializes a new instance of the <see cref="AncestorsDataTypeTreeController"/> class, which manages operations related to ancestor data type trees in the Umbraco CMS.
/// </summary>
/// <param name="entityService">Service used for entity-related operations.</param>
/// <param name="flagProviders">A collection of providers that supply flags for tree nodes.</param>
/// <param name="dataTypeService">Service used for data type management operations.</param>
/// Initializes a new instance of the <see cref="RootDataTypeTreeController"/> class, which manages the root of the data type tree in the Umbraco management API.
/// </summary>
/// <param name="entityService">Service used for entity operations within the tree.</param>
/// <param name="flagProviders">A collection of providers that supply flags for tree nodes.</param>
/// <param name="dataTypeService">Service used for data type management and retrieval.</param>
/// Initializes a new instance of the <see cref="SiblingsDataTypeTreeController"/> class, which manages operations related to sibling data type trees in the Umbraco CMS.
/// </summary>
/// <param name="entityService">Service used for entity operations within the CMS.</param>
/// <param name="flagProviders">A collection of providers that supply flags for tree nodes.</param>
/// <param name="dataTypeService">Service used for managing data types.</param>
/// Gets a paged collection of data type tree items that are siblings of the specified data type identifier.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="target">The unique identifier of the data type whose siblings are to be retrieved.</param>
/// <param name="before">The number of sibling items to retrieve before the target item.</param>
/// <param name="after">The number of sibling items to retrieve after the target item.</param>
/// <param name="foldersOnly">If set to <c>true</c>, only folders will be included in the results; otherwise, both folders and data types are returned.</param>
/// <returns>A task representing the asynchronous operation. The task result contains an <see cref="ActionResult{T}"/> with a <see cref="SubsetViewModel{T}"/> of <see cref="DataTypeTreeItemResponseModel"/> representing the sibling items.</returns>
/// Initializes a new instance of the <see cref="UpdateDataTypeController"/> class, responsible for handling data type update operations in the management API.
/// </summary>
/// <param name="dataTypeService">Service used to manage data types.</param>
/// <param name="backOfficeSecurityAccessor">Accessor for back office security context.</param>
/// <param name="dataTypePresentationFactory">Factory for creating data type presentation models.</param>
@@ -35,6 +46,12 @@ public class CreateDictionaryController : DictionaryControllerBase
_authorizationService=authorizationService;
}
/// <summary>
/// Creates a new dictionary item using the details provided in the request model.
/// </summary>
/// <param name="cancellationToken">Token to monitor for cancellation requests.</param>
/// <param name="createDictionaryItemRequestModel">The model containing the details of the dictionary item to create, including translations.</param>
/// <returns>An <see cref="IActionResult"/> indicating the result of the create operation, including possible status codes for success or failure.</returns>
/// Initializes a new instance of the <see cref="DeleteDictionaryController"/> class, used for handling requests to delete dictionary items in the Umbraco CMS.
/// </summary>
/// <param name="dictionaryItemService">Service for managing dictionary items.</param>
/// <param name="backOfficeSecurityAccessor">Accessor for back office security context.</param>
/// Initializes a new instance of the <see cref="ExportDictionaryController"/> class, providing services for dictionary item management and XML serialization.
/// </summary>
/// <param name="dictionaryItemService">Service used to manage dictionary items.</param>
/// <param name="entityXmlSerializer">Service used to serialize entities to XML.</param>
/// Exports the dictionary item identified by the provided <paramref name="id"/> as a downloadable file.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="id">The unique identifier of the dictionary item to export.</param>
/// <param name="includeChildren">If <c>true</c>, child dictionary items will also be included in the export; otherwise, only the specified item is exported.</param>
/// <returns>
/// A <see cref="FileContentResult"/> containing the exported dictionary data as a file if the dictionary item is found;
/// otherwise, a <see cref="NotFoundResult"/> if the item does not exist.
/// Initializes a new instance of the <see cref="ImportDictionaryController"/> class, which handles dictionary item import operations in the Umbraco backoffice API.
/// </summary>
/// <param name="dictionaryItemImportService">Service used to import dictionary items.</param>
/// <param name="backOfficeSecurityAccessor">Accessor for back office security context.</param>
/// Imports a dictionary from a provided UDT file upload.
/// </summary>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the import operation.</param>
/// <param name="importDictionaryRequestModel">The model containing the uploaded UDT file and optional parent dictionary item information.</param>
/// <returns>
/// An <see cref="IActionResult"/> indicating the result of the import operation:
/// returns <c>201 Created</c> on success, <c>400 Bad Request</c> for invalid file types or content, and <c>404 Not Found</c> if the parent or file is missing.
/// Retrieves a collection of dictionary items matching the specified IDs.
/// </summary>
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
/// <param name="ids">A set of dictionary item IDs to retrieve.</param>
/// <returns>A task representing the asynchronous operation. The result contains an <see cref="IActionResult"/> with the collection of dictionary items.</returns>
/// Initializes a new instance of the <see cref="MoveDictionaryController"/> class, responsible for handling dictionary item move operations in the management API.
/// </summary>
/// <param name="dictionaryItemService">Service used to manage dictionary items.</param>
/// <param name="backOfficeSecurityAccessor">Accessor for back office security context.</param>
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.