Repository navigation
[6.x] Move the legacy control panel JavaScript to modules and the Yii2 adapter - #20276
brianjhanson wants to merge 58 commits into
Conversation
CraftCopyAttribute, CraftGlobalSidebar, and CraftTooltip were never imported into the legacy cp bundle; @craftcms/ui and <cp-global-sidebar> replaced them. Craft.ImageUpload's only consumer was the rebrand script, whose asset bundle no longer registered it, so both go along with the generalsettings webpack package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core never instantiates it, but plugins still call Craft.LivePreview.init() from their edit pages. It now ships in the adapter's cpcompat bundle, loaded CP-wide by CpCompatAsset. Core's two remaining references were no-ops, since Craft.LivePreview.instances is never populated, so they're dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each module's index.ts now only defines its element and exports. Globals core still calls move to globals.ts, which index.ts imports. Globals only plugins call move to compat.ts, which only the yii2-adapter's cp-compat.ts imports. Moving a global to the adapter is now a one-line move between the two files. Adapter-only from this commit: Craft.AssetImageEditor, Craft.SortableCheckboxSelect, Craft.GroupedEntryTypeManager, Craft.RecoveryCodesSetup and Craft.TagSelectInput, which core no longer calls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Uploads, highlighter, AuthChallengeForm, createElementSelectorModal and the element selector controller registry are now exports of the @craftcms/cp import-map module rather than Craft.* globals, so control panel plugin code imports them. The Yii2 adapter keeps Craft.createElementSelectorModal and Craft.highlighter for Craft 5 plugins. Pages outside the control panel still get Craft.Uploads from the standalone uploads entry, since they have no import map. SlideoutPanel no longer assumes window.Craft exists; it was relying on a module that happened to create it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Craft.commandPalette is new in 6.0, so it moves to a CommandPalette export of the @craftcms/cp import-map module instead of becoming a global the adapter has to carry. Craft.charts dates from Craft 5 and core's legacy New Users widget still calls it, so it gets the globals.ts split. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The class now lives in resources/js/common/utils/promise-queue.ts on @craftcms/garnish Base, without jQuery. The legacy bundle imports it and still assigns Craft.Queue and Craft.queue where Queue.js did, since Craft.cp uses the queue while that bundle evaluates. A failed job no longer leaves an unhandled rejection behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Craft.AssetsFieldSettings and Craft.ElementFieldSettings only serve the legacy relation field settings templates, which only the adapter's LegacyRelationFieldSettings renders; core builds those settings with settingsUi(). They now ship unchanged in the cpcompat bundle, loaded CP-wide by CpCompatAsset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The trim/startsWith/remove* family, escapeRegex, escapeChars, upper/lowercaseFirst, uuid, randomString, formatInputId, namespaceInputName and namespaceId now live in resources/js/common/craft/. Craft.js assigns them, so Craft.trim() and the rest keep working for plugins, and the modern modules that reached through the global import them instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
findDeltaData, findModifiedDeltaNames, groupParams and the private _groupParamsByDeltaNames now live in resources/js/common/craft/delta.ts, with a jQuery-compatible param() serializer in params.ts that's tested against $.param itself. Craft.js assigns them for plugins, and the CP modal, CP screen slideout and inline editing import them directly. The inline editing test now runs the real delta logic instead of a stub that returned the expected result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
getUrl, getCpUrl, getSiteUrl and getActionUrl now live in resources/js/common/craft/url.ts, read their base URLs from the CP config at call time, and encode params with the jQuery-compatible param(). The script-name and path-param branches are gone: Craft 6 never sends pathParam or scriptName, so they couldn't change the result. Output was checked against the legacy implementation. Craft.js assigns them for plugins, and the modern modules that called Craft.getCpUrl()/getActionUrl() import them. Their tests now set the base URLs rather than stubbing the helpers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Relation inputs pass handles like '> .element > .chip-content > ...', which jQuery's find() treated as relative to the item but native querySelector() rejects, so a sortable relation input with existing items threw while initializing. A leading '>' is now scoped to the item. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Asset fields drew their upload progress with the legacy Craft.ProgressBar, whose stylesheet Craft 6 never loads, so the bar rendered unstyled and the shade over the field never appeared. They now use the <craft-progress-bar> element, which exposes a labelled progressbar to assistive tech, with a small stylesheet for the overlay. Progress is still announced every few seconds while an upload runs. Craft.ProgressBar stays in the legacy bundle for the legacy asset index. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # packages/craftcms-garnish/src/drag/base-drag.ts # packages/craftcms-garnish/tests/drag.test.ts # yii2-adapter/resources/js/cp-compat.ts
element-selector-modals/body returned the legacy ElementIndexHtml markup alongside the index props, but every modal now renders the Vue index from props, so the markup was rendered on each open and thrown away. The response is now just props, and the request params and status narrowing that only fed the markup are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The elementIndex() Twig function and ElementIndexHtml rendered the legacy jQuery element index, and nothing in core used them. They now live in the adapter, next to craft\helpers\Cp::elementIndexHtml() and the nested element manager that call them. _layouts/elementindex only drew the legacy index when the shell wasn't collecting the screen, which nothing triggers any more, so the layout now always declares the Vue index. Its empty initJs block stays for child templates that extend it. craft.cp.screenCollecting() lost its only caller and is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Craft.BaseElementIndex, its views, the per-type indexes, the structure view and ProgressBar now ship in the adapter's cpcompat bundle as one element-index entry, along with Craft.createElementIndex() and Craft.registerElementIndexClass(). Core renders every element index with the Vue index, so none of it was used without the adapter. The legacy cp bundle drops from 406 KB to 265 KB. The globals only those classes used (ElementTableSorter, IntervalManager, PromptHandler and openCustomizeSourcesModal) move to compat.ts, and the Vue index's Customize Sources action imports the modal directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the legacy dashboard, which only the adapter loads, and plugins use the legacy admin table, so it now ships in the cpcompat bundle. The editable table imports DataTableSorter instead of reaching for Craft.DataTableSorter, leaving that global to the adapter as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Craft.t() assigned 'app' to its category argument instead of passing the caller's category through, so plugin translations were never found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 151 Craft.t('app', …) calls in resources/js and the adapter's
nested element manager now use @craftcms/ui's t(). Each control panel
entry first seeds its translations from window.Craft, because custom
elements already on the page upgrade, and translate their labels, while
their modules are still loading, before the CP bootstrap runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core modules called Craft.sendActionRequest(), which only exists because the legacy bundle defines it. They now use actionClient, which sends the same registered-asset headers and resolves action paths, root-relative URLs and absolute URLs the same way. The CP modal and CP screen slideout still accept plugin-supplied axios options, so their screen loads go through sendLegacyRequest() with actionClient, and their form submissions post to the CP URL as before. Craft.sendActionRequest() stays for plugins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core modules now import appendHeadHtml() and appendBodyHtml() from @craftcms/ui instead of calling the Craft.* versions, so head HTML they load lands above the control panel stylesheet like the Vue screens' does. The CP modal, which didn't wait between the two, now appends the body HTML once the head's scripts have loaded. Craft.appendHeadHtml() and appendBodyHtml() keep their queue and still append to the end of <head>, but use the same implementation. Their duplicate check reads the live DOM instead of a list captured on first use, so they no longer re-run a script something else added since. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
addActionsToChip, setElementAttributes, escapeHtml and hasMousePointerEvents now live in resources/js/common/craft/, without jQuery except for the disclosure menu fallback that old chip markup still needs. Core modules import them, and Craft.js assigns them so the Craft.* names keep working for plugins. setElementAttributes keeps the legacy behavior plugins may depend on: it accepts a selector or a collection, applies to every element in it, and adds px to bare numbers in a style object as jQuery's css() did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core modules now read text direction, the page trigger, element type names and handle casing from ConfigService, and import cookie, focus, broadcast and elevated-session helpers directly. The Craft.* members stay in place for plugins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@craftcms/ui now exports a single create(tag, props, ...children) that types props from HTMLElementTagNameMap, so every component gets checked properties without a factory of its own. The per-component factories only translated the legacy Craft.ui config keys, so they move next to the Craft.ui patch in resources/js/modules/ui/legacy, which UI.js imports. createCopyTextPrompt opens a dialog rather than building a control, so it stays in @craftcms/ui as showCopyTextPrompt(). Core's button and copy prompt callers now use create() and showCopyTextPrompt(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The field error helpers (addErrorsToField, clearErrorsFromField, the error summary helpers and findTabAnchorForField) now live in common/craft/field-errors.ts without jQuery, and Craft.ui's methods call them. Core fetches icon SVGs through iconSvg(), which requests each name once, and builds the matrix default-columns select with create(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core called Craft.cp.displayNotice(), displaySuccess(), displayError() and displayNotification() in 111 places. They now import showNotice(), showSuccess() and showError() from the messages module, which every message already went through for deduping. showMessage() returns the notification so callers can close it, and the functions are exported from @craftcms/cp for plugins. Craft.cp's methods are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core's seven Craft.cp.runQueue() calls now call QueueService.getInstance().runQueue(), which Craft.cp.runQueue() already delegated to. Also drops test stubs for Craft.cp.display*() that nothing calls any more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core's Craft.cp.elementThumbLoader.load() calls use a shared loader from the element-thumb-loader module instead. Craft.cp.elementThumbLoader is unchanged for plugins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
modules/elements/clipboard owns copied elements: localStorage, the cross-tab broadcast, listeners and paste. Core and the @craftcms/cp exports call it directly; Craft.cp's clipboard methods delegate to it. The "copied" card is still the legacy ElementCopyNotification. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
common/announcer finds the live region when a message is announced: the top modal layer's, else the page's. This replaces CP.js's layer tracking. useAnnouncer() and Craft.cp.announce() both go through it, so Vue code inside a modal is heard and Craft.cp.announce() works on Inertia pages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every element editor in core is the Vue one, slideouts included: Inertia requests for elements/edit render elements/Edit before prepareEditor() runs. So the slideout bridge that ran Craft.ElementEditor never activated, and is removed along with the unreachable controller branch that fed it. ElementEditor.js now ships in the adapter's cpcompat bundle, and the Craft.ElementEditorSlideout global is set by the adapter. The legacy Validate menu item gets its element ID from PHP instead of the editor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copy, Delete, and the asset and user items in getActionMenuItems() now carry a craft:element-action event action naming the same behavior actionMenuDescriptors() uses, and a page-wide listener runs it through the Vue editor's dispatcher. Server-rendered chips, cards and screens no longer need Craft.cp, Craft.createForm() or Craft.sendActionRequest() for them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Messages, the clipboard's copied card and upload notices now draw through a TypeScript Notification, and <cp-messages> manages the stack it shows them in: offsets, the five-visible limit, expanding on hover, press or focus, and pausing timers while expanded or hidden. Craft.cp.display*() still works and routes here. A prebuilt Craft.CP.Notification from a plugin still draws itself, but CP.js's stack methods now delegate to <cp-messages>, so it joins the same stack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core no longer needs it: messages, the clipboard, announcements, the queue and element thumbnails all run from modules, and its page behaviors only ever applied to the legacy cp.twig document. CP.js now ships in the adapter's cpcompat bundle. Its last core callers move off it: preview count badges expand through a delegated listener instead of inline Craft.cp handlers, the focal point editor announces through a craft:announce event, and Craft.js shows errors through the craft-message event. The cross-tab queue handler in Craft.js is gone; it called Craft.cp.getNextJobDelay(), which doesn't exist, and QueueService already keeps tabs in step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Element select inputs, slideouts, CP modals, the component select, two-step verification, the Vue element editor and nested element operations now use modules instead of Craft.getElementInfo(), setElementSize(), animate(), refreshComponentInstances(), trapFocusWithin(), useMobileStyles(), downloadFromUrl() and Craft.broadcaster. Two-step verification also builds its setup slideout directly, rather than through a global only the adapter sets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The updater page carries its action prefix and starting state in data attributes, and legacy.ts starts a TypeScript Updater from them, instead of inline JS constructing Craft.Updater. The focal point editor moves into core: the preview modal starts it on image previews that ask for it, rather than the template loading the legacy FocalPoint bundle and constructing Craft.FocalPoint. Neither needs Craft.js any more. The plugins page no longer registers the legacy PluginManager.js, which nothing on it used. Customize Sources gets uuid() from the strings module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core no longer loads the legacy cp.js bundle (Craft.js and Craft.queue); CpCompatAsset loads it ahead of the adapter's other legacy files. The last core callers move off it first. The licensing issues screen starts its refresh button and countdown from a module, the volume select builds its CP URL in Twig, and flashed broadcasts go through a craft:broadcast event that core relays. The legacy disclosure menu and menu button plugins are only called when they're there, since only legacy markup needs them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plugins that registered CpAsset on front-end pages used to get Craft.js with it. Since Craft.js moved to the adapter it only loaded on CP requests, so those pages lost the Craft helpers. A new CraftJsAsset loads it, and both the Yii CpAsset shim and CpCompatAsset depend on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing has loaded the legacy cp.css since September, so its SCSS, the Craft icon font and the images only it used are deleted. The CP favicons move to Vite's public directory, and the adapter's relation field settings use core's view-mode icons. The legacy cp bundle keeps only Craft.js, the queue and the default legacy widget image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rver The legacy CP stylesheet is gone, so the dev bootstrap would have rebuilt every legacy bundle on each run. It checks for jQuery's build instead. The a11y instructions no longer point at the deleted stylesheet either. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Craft.js, the queue and the default legacy widget image were all that was left in the legacy cp bundle, and only the Yii2 adapter loads them. They move into cpcompat with the rest of the adapter's legacy scripts, as a craft.js entry, and the cp bundle is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the adapter Nothing in core uses them any more. Core's CpAsset stops loading them, and the adapter's CraftJsAsset loads them for plugins instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live Preview resized its frames through the window.iFrameResize global that CpAsset loaded; it imports iframe-resizer now. Core's selectize inputs already render <craft-combobox>, so nothing in core uses Selectize. Both bundles move to the adapter's CraftJsAsset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a1a41f-35f1-75f6-a070-f628cc4e7276 Co-authored-by: Amp <amp@ampcode.com> # Conflicts: # packages/craftcms-legacy/cp/src/css/_menu.scss # resources/js/modules/field-layout-designer/element.ts # resources/js/modules/ui/legacy/slide-picker.ts # resources/templates/_includes/forms/entry-type-select/selection-settings.twig # yii2-adapter/src/View/LegacyAssets/CpCompatAsset.php
The focal point editor moved into core's image previews, so core no longer has a FocalPointAsset for the deprecated adapter bundle to delegate to. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a41f-35f1-75f6-a070-f628cc4e7276 Co-authored-by: Amp <amp@ampcode.com>
# Conflicts: # resources/js/modules/ui/nested-elements/useNestedElementOperations.ts
There was a problem hiding this comment.
🟡 Changes recommended
The module-private focal-point instance is disconnected from the preview lifecycle, leaving resize and teardown code dependent on an unassigned global and breaking marker repositioning, editor cleanup, and pending-save flushing.
1 open issue
What changed in this PR
Moves legacy control-panel JavaScript out of core into TypeScript modules and the Yii2 adapter, preserving plugin compatibility while exposing modern APIs through @craftcms/cp.
Changes:
- Separates module exports from legacy globals and adapter-only compatibility code.
- Migrates core consumers to module services and declarative UI initialization.
- Updates templates, assets, builds, tests, and documentation; removes obsolete legacy files.
This pull request requires changes. Three unresolved issues block approval:
- Critical —
resources/templates/assets/_previews/image.twig:16: The new focal-point instance is disconnected from preview resize and teardown handling, breaking marker repositioning and cleanup/pending-save flushing. - Moderate —
src/Auth/Methods/RecoveryCodes.php:67: The new action descriptor conflicts with the Password page’s string-based contract, causing an array-to-string warning and passing an incompatible object to its action handler. - Moderate —
src/Http/Mixins/SessionMixin.php:33: Broadcast events can fire before the asynchronously installed relay on Twig pages, losing cross-tab notifications.
Verification was limited to source review; tests, builds, and browser accessibility checks were not run.
| File | Description |
|---|---|
yii2-adapter/src/Mixins/NestedElementManagerMixin.php |
Uses the adapter’s legacy index renderer. |
yii2-adapter/resources/templates/_includes/forms/volume.twig |
Generates the slideout URL server-side. |
yii2-adapter/resources/templates/_includes/forms/customSelect.twig |
Guards legacy menu initialization. |
yii2-adapter/resources/js/slide-picker-compat.browser.test.ts |
Imports the relocated UI compatibility bundle. |
yii2-adapter/resources/js/matrix/matrix-input.ts |
Imports the relocated paste-button builder. |
yii2-adapter/resources/js/matrix/matrix-entry.ts |
Uses the module URL helper. |
yii2-adapter/resources/js/cp-compat.ts |
Loads translations and adapter compatibility registrations. |
yii2-adapter/legacy/web/twig/Extension.php |
Registers the legacy index Twig function. |
yii2-adapter/legacy/web/assets/focalpoint/FocalPointAsset.php |
Retires standalone focal-point asset registration. |
yii2-adapter/legacy/web/assets/cp/CpAsset.php |
Registers the adapter’s legacy Craft helpers. |
yii2-adapter/legacy/helpers/Cp.php |
References the adapter index renderer. |
yii2-adapter/legacy/base/WidgetTrait.php |
Updates the relocated image URL. |
tests/Unit/Twig/Templates/CheckboxSelectTemplateTest.php |
Removes the obsolete host-class expectation. |
tests/Unit/Cp/Components/CheckboxSelectTest.php |
Updates checkbox-select markup expectations. |
tests/Unit/Cp/Components/ActionMenuTest.php |
Covers elevated-session action descriptors. |
tests/Feature/Integration/UtilityPageAssetsTest.php |
Checks the reduced core asset bundle. |
tests/Feature/Image/RasterTest.php |
Uses a dedicated font fixture. |
tests/Feature/Http/Controllers/PluginStore/InstallControllerTest.php |
Checks declarative updater initialization. |
tests/Feature/Http/Controllers/Elements/ElementSelectorModalControllerTest.php |
Expects props without legacy index HTML. |
tests/Feature/Cp/PreviewHtmlTest.php |
Checks declarative preview-badge hooks. |
src/View/LegacyAssets/UpdaterAsset.php |
Stops registering the legacy updater script. |
src/View/LegacyAssets/GeneralSettingsAsset.php |
Removes obsolete commented registrations. |
src/View/LegacyAssets/FocalPointAsset.php |
Deletes the obsolete core asset bundle. |
src/View/LegacyAssets/CpAsset.php |
Removes legacy CP JavaScript and adapter-only dependencies. |
src/Twig/Variables/Cp.php |
Removes the obsolete screen-collection helper. |
src/Http/ViewModels/ContentIndexViewModel.php |
Removes a stale renderer reference from documentation. |
src/Http/Mixins/SessionMixin.php |
Emits DOM events for broadcasts; startup timing remains unresolved. |
src/Http/Controllers/PluginsController.php |
Drops legacy plugin-manager asset registration. |
src/Http/Controllers/Elements/EditElementController.php |
Removes unused Inertia legacy-editor settings. |
src/Http/Controllers/BaseUpdaterController.php |
Passes updater configuration through template data. |
src/FieldLayout/LayoutElements/Assets/AltField.php |
Removes the legacy text-enhancement class. |
src/Field/Link.php |
Removes legacy instruction-display classes. |
src/Element/ElementIndexState.php |
Documents the adapter-owned legacy index. |
src/Cp/Html/PreviewHtml.php |
Replaces inline handlers with preview-badge data attributes. |
src/Cp/Components/InputDateTime.php |
Enables the component-owned clear button. |
src/Cp/Components/CheckboxSelect.php |
Removes the obsolete host class. |
src/Cp/Components/ActionMenu.php |
Preserves elevated-session requirements in HTTP actions. |
src/Cp/CommandPalette/CommandPaletteItem.php |
Documents the module registration API. |
src/Auth/Methods/RecoveryCodes.php |
Returns a POST-download descriptor; consumer contracts need updating. |
scripts/ensure-built.mjs |
Uses jQuery as the legacy-build sentinel. |
resources/translations/en/app.php |
Repositions the upload-progress translation. |
resources/templates/users/_auth-methods.twig |
Replaces the legacy disclosure menu with ActionMenu. |
resources/templates/settings/entry-types/_selection-settings.twig |
Removes the legacy text-enhancement class. |
resources/templates/assets/_previews/image.twig |
Declares focal-point hooks; preview lifecycle integration remains unresolved. |
resources/templates/_special/updater.twig |
Embeds updater state for module initialization. |
resources/templates/_layouts/cp.twig |
Guards the adapter-only update-check call. |
resources/templates/_layouts/components/alerts.twig |
Guards adapter-only alert loading. |
resources/templates/_layouts/base.twig |
Uses public CP asset URLs for icons. |
resources/templates/_components/fieldtypes/PlainText/input.twig |
Removes the legacy text-enhancement class. |
resources/templates/_components/auth/methods/TOTP/setup.twig |
Emits message events instead of calling Craft.cp. |
resources/js/uploads.ts |
Documents the standalone upload entry point. |
resources/js/pages/users/Passkeys.vue |
Uses module-based error notifications. |
resources/js/pages/assets/Index.vue |
Reads the pagination key through the URL helper. |
resources/js/pages/assets/AssetUploadButton.test.ts |
Mocks the module queue service. |
resources/js/modules/uploader/uploader.ts |
Uses module-based upload error reporting. |
resources/js/modules/uploader/uploader.test.ts |
Removes the legacy notification mock. |
resources/js/modules/uploader/upload-queue.ts |
Uses module-based cancellation errors. |
resources/js/modules/uploader/upload-notification.ts |
Uses module notifications and native close-button access. |
resources/js/modules/uploader/picker.test.ts |
Mocks the module error reporter. |
resources/js/modules/uploader/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/uploader/globals.ts |
Registers uploader compatibility globals. |
resources/js/modules/uploader/asset-upload-queue.ts |
Uses module notifications and queue execution. |
resources/js/modules/uploader/asset-upload-queue.test.ts |
Updates queue and notification mocks. |
resources/js/modules/ui/useUiForm.ts |
Reports form failures through module notifications. |
resources/js/modules/ui/useInertiaTable.ts |
Reads the configured pagination key through a helper. |
resources/js/modules/ui/UiModal.vue |
Uses module-based success notices. |
resources/js/modules/ui/UiModal.browser.test.ts |
Removes the legacy error-display mock. |
resources/js/modules/ui/README.md |
Documents adapter-only UI compatibility loading. |
resources/js/modules/ui/nested-elements/useNestedElementsQuery.ts |
Uses the pagination-key helper. |
resources/js/modules/ui/nested-elements/useNestedElementsQuery.test.ts |
Removes legacy pagination configuration. |
resources/js/modules/ui/nested-elements/NestedElementsControl.test.ts |
Initializes element names through ConfigService. |
resources/js/modules/ui/nested-elements/NestedElements.test.ts |
Removes the legacy notice mock. |
resources/js/modules/ui/nested-elements/nested-elements.ts |
Uses module-based element naming and clipboard types. |
resources/js/modules/ui/nested-elements/nested-elements-control-host.test.ts |
Removes legacy clipboard and pagination mocks. |
resources/js/modules/ui/legacy/switch.ts |
Corrects the relocated component type import. |
resources/js/modules/ui/legacy/slide-picker.ts |
Corrects the relocated component type import. |
resources/js/modules/ui/legacy/input-password.ts |
Updates component and slotted-input imports. |
resources/js/modules/ui/legacy/input-color.ts |
Updates component, translation, and input imports. |
resources/js/modules/ui/legacy/index.ts |
Exports relocated legacy UI builders. |
resources/js/modules/ui/layout-component-settings-ui-host.ts |
Uses actionClient for settings refreshes. |
resources/js/modules/ui/ElementSitesControl.vue |
Uses module-based deletion errors. |
resources/js/modules/ui/element-select/usePasteableElements.ts |
Uses module element names and clipboard clearing. |
resources/js/modules/ui/dashboard-widget-settings-ui-host.ts |
Uses actionClient for widget settings. |
resources/js/modules/ui/compat.test.ts |
Imports the explicit compatibility entry point. |
resources/js/modules/tabs/tabs.ts |
Guards legacy menus and uses module direction detection. |
resources/js/modules/tabs/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/tabs/globals.ts |
Registers the tabs compatibility global. |
resources/js/modules/sortable-checkbox-select/compat.ts |
Registers the adapter-only legacy constructor. |
resources/js/modules/slideout/compat.ts |
Registers the compatibility-wrapped legacy editor slideout. |
resources/js/modules/queue/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/queue/globals.ts |
Registers the queue-service compatibility global. |
resources/js/modules/prompt-handler/index.ts |
Removes direct global registration. |
resources/js/modules/prompt-handler/compat.ts |
Registers the adapter-only prompt handler. |
resources/js/modules/preview-file-modal/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/preview-file-modal/globals.ts |
Registers the preview-modal compatibility global. |
resources/js/modules/notifications/store.ts |
Uses module-based notification errors. |
resources/js/modules/notifications/store.test.ts |
Checks the module error reporter. |
resources/js/modules/navigation/components/cp-queue-indicator.ts |
Uses the module CP URL helper. |
resources/js/modules/navigation/components/cp-global-sidebar.ts |
Uses module cookie helpers. |
resources/js/modules/messages/useMessages.ts |
Reuses shared notification functions. |
resources/js/modules/link-field/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/link-field/globals.ts |
Registers link-field compatibility globals. |
resources/js/modules/interval-manager/interval-manager.ts |
Clarifies the remaining legacy consumer. |
resources/js/modules/interval-manager/index.ts |
Removes direct global registration. |
resources/js/modules/interval-manager/compat.ts |
Registers the adapter-only interval manager. |
resources/js/modules/input-generators/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/input-generators/handle-generator.ts |
Reads casing from ConfigService. |
resources/js/modules/input-generators/globals.ts |
Registers input-generator compatibility globals. |
resources/js/modules/image-editor/open-asset-image-editor.ts |
Uses module broadcasting, queue execution, and errors. |
resources/js/modules/image-editor/index.ts |
Separates exports from global registration. |
resources/js/modules/image-editor/globals.ts |
Registers the markup-facing image-editor helper. |
resources/js/modules/image-editor/compat.ts |
Registers the adapter-only legacy editor class. |
resources/js/modules/highlight/compat.ts |
Clarifies compatibility use and removes its export. |
resources/js/modules/grouped-entry-type-manager/README.md |
Updates documented legacy dependencies. |
resources/js/modules/grouped-entry-type-manager/index.ts |
Removes compatibility registration and ancillary exports. |
resources/js/modules/grouped-entry-type-manager/EntryTypeOverrideSettings.vue |
Uses module field errors and notifications. |
resources/js/modules/grouped-entry-type-manager/compat.ts |
Registers the legacy constructor and nested class. |
resources/js/modules/grid/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/grid/grid.ts |
Uses module direction helpers for positioning. |
resources/js/modules/grid/globals.ts |
Registers the grid compatibility global. |
resources/js/modules/form-observer/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/form-observer/globals.ts |
Registers the form-observer compatibility global. |
resources/js/modules/focal-point/focal.scss |
Supplies relocated focal-point marker styles. |
resources/js/modules/field-toggle/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/field-toggle/globals.ts |
Registers the field-toggle compatibility global. |
resources/js/modules/field-toggle/field-toggle.ts |
Reads switch state from its current checked property. |
resources/js/modules/field-toggle/field-toggle.test.ts |
Covers checked-property precedence. |
resources/js/modules/field-layout-designer/README.md |
Updates documented legacy dependencies. |
resources/js/modules/field-layout-designer/LayoutComponentSettings.vue |
Uses actionClient for settings refreshes. |
resources/js/modules/field-layout-designer/index.ts |
Delegates compatibility registration to a separate module. |
resources/js/modules/field-layout-designer/globals.ts |
Registers the designer and nested compatibility classes. |
resources/js/modules/field-layout-designer/field-layout-designer.test.ts |
Configures URLs without mocking legacy helpers. |
resources/js/modules/field-layout-designer/field-layout-designer.ce.ts |
Uses the explicit legacy-UI initializer. |
resources/js/modules/entry-mover/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/entry-mover/globals.ts |
Registers the entry-mover compatibility global. |
resources/js/modules/elements/live-preview/useLivePreview.ts |
Removes the global iframe-resizer declaration. |
resources/js/modules/elements/live-preview/PreviewLayout.vue |
Imports iframe resizing directly. |
resources/js/modules/elements/index/save-inline-elements.ts |
Uses module-based save errors. |
resources/js/modules/elements/index/element-actions.ts |
Uses module-based action notices and errors. |
resources/js/modules/elements/index/copy-elements.ts |
Copies through the module clipboard API. |
resources/js/modules/elements/index/composables/useElementIndexVisits.ts |
Uses the pagination-key helper. |
resources/js/modules/elements/index/composables/useElementIndexSort.test.ts |
Removes legacy pagination configuration. |
resources/js/modules/elements/index/composables/useCustomizeSources.ts |
Opens source customization through a module import. |
resources/js/modules/elements/index/composables/useCustomizeSources.test.ts |
Mocks the module customization entry point. |
resources/js/modules/elements/index/components/ElementIndexPage.filters.test.ts |
Configures pagination through ConfigService. |
resources/js/modules/elements/index/components/ElementIndex.test.ts |
Removes legacy pagination configuration. |
resources/js/modules/elements/index/components/ElementBulkActionsBar.vue |
Uses module-based action errors. |
resources/js/modules/elements/element-action-events.ts |
Dispatches server-rendered element action events. |
resources/js/modules/elements/composables/useBulkActionSelection.ts |
Updates clipboard behavior documentation. |
resources/js/modules/element-thumb-loader/index.ts |
Re-exports the separated loader implementation. |
resources/js/modules/element-thumb-loader/element-thumb-loader.test.ts |
Imports the relocated legacy CP implementation. |
resources/js/modules/element-table-sorter/index.ts |
Removes direct global registration. |
resources/js/modules/element-table-sorter/compat.ts |
Registers the adapter-only element-table sorter. |
resources/js/modules/element-selector-modal/volume-folder-selector-modal.test.ts |
Uses props-only index responses. |
resources/js/modules/element-selector-modal/useModalElementIndex.test.ts |
Removes legacy pagination configuration. |
resources/js/modules/element-selector-modal/useElementSelectorController.test.ts |
Uses props-only index responses. |
resources/js/modules/element-selector-modal/index.test.ts |
Checks separation of core and compatibility globals. |
resources/js/modules/element-selector-modal/globals.ts |
Registers the volume-folder modal compatibility global. |
resources/js/modules/element-selector-modal/ElementSelectorModal.test.ts |
Removes obsolete HTML response fixtures. |
resources/js/modules/element-selector-modal/compat.ts |
Registers the adapter-only selector factory. |
resources/js/modules/element-select-input/index.ts |
Delegates global registration to separate modules. |
resources/js/modules/element-select-input/globals.ts |
Registers base and entry input compatibility globals. |
resources/js/modules/element-select-input/entry-select-input.ts |
Uses module action requests and URLs. |
resources/js/modules/element-select-input/element-select-input.ce.ts |
Uses the explicit legacy-UI initializer. |
resources/js/modules/element-select-input/compat.ts |
Registers the adapter-only tag input. |
resources/js/modules/element-select-input/base-element-select-input.test.ts |
Mocks actionClient instead of legacy requests. |
resources/js/modules/element-deletion-manager/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/element-deletion-manager/globals.ts |
Registers the deletion-manager compatibility global. |
resources/js/modules/element-action-trigger/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/element-action-trigger/globals.ts |
Registers the action-trigger compatibility global. |
resources/js/modules/editable-table/index.ts |
Removes direct compatibility wrapping and registration. |
resources/js/modules/editable-table/compat.ts |
Registers compatibility-wrapped table and row classes. |
resources/js/modules/data-table-sorter/index.ts |
Removes direct global registration. |
resources/js/modules/data-table-sorter/data-table-sorter.ts |
Clarifies module versus legacy consumers. |
resources/js/modules/data-table-sorter/compat.ts |
Registers the adapter-only table sorter. |
resources/js/modules/customize-sources/index.ts |
Removes direct global registration. |
resources/js/modules/customize-sources/compat.ts |
Registers the adapter-only customization helper. |
resources/js/modules/cp-modal/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/cp-modal/globals.ts |
Registers the CP-modal compatibility global. |
resources/js/modules/component-select/README.md |
Updates documented legacy dependencies. |
resources/js/modules/command-palette/run.ts |
Uses module-based action notifications. |
resources/js/modules/command-palette/registry.ts |
Documents the module registration API. |
resources/js/modules/command-palette/index.ts |
Removes the legacy command-palette global. |
resources/js/modules/command-palette/components/UiFormView.test.ts |
Removes the legacy error-display mock. |
resources/js/modules/command-palette/components/CommandPalette.vue |
Uses module-based palette notifications. |
resources/js/modules/chart/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/chart/globals.ts |
Registers the chart compatibility namespace. |
resources/js/modules/auth/elevated-session/index.test.ts |
Covers action-driven elevated-session requests. |
resources/js/modules/auth/components/auth-challenge-form.ts |
Removes global registration and documents module imports. |
resources/js/modules/auth-method-setup/index.ts |
Separates exports from global registration. |
resources/js/modules/auth-method-setup/globals.ts |
Registers the markup-facing setup constructor. |
resources/js/modules/auth-method-setup/compat.ts |
Registers the adapter-only recovery-code setup constructor. |
resources/js/modules/assets/replaceAssetFile.ts |
Uses module broadcasting and notifications. |
resources/js/modules/assets/composables/useAssetIndexItemBehavior.ts |
Uses the pagination-key helper. |
resources/js/modules/assets/composables/useAssetIndexItemBehavior.test.ts |
Removes legacy pagination configuration. |
resources/js/modules/assets/composables/useAssetFolderActions.test.ts |
Removes legacy notification mocks. |
resources/js/modules/asset-select-input/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/asset-select-input/globals.ts |
Registers the asset-input compatibility global. |
resources/js/modules/asset-select-input/asset-select-input.css |
Supplies upload-progress overlay styles. |
resources/js/modules/asset-mover/index.ts |
Delegates global registration to a separate module. |
resources/js/modules/asset-mover/globals.ts |
Registers the asset-mover compatibility global. |
resources/js/modules/ai/skills/AiSkills.vue |
Uses module-based deletion errors. |
resources/js/modules/ai/assistant/AssistantConversationMenu.vue |
Uses module-based conversation errors. |
resources/js/modules/admin-table/legacy-admin-table.test.ts |
Removes the legacy request mock. |
resources/js/modules/admin-table/components/LegacyAdminTable.vue |
Uses module requests and notifications. |
resources/js/common/types/iframe-resizer.d.ts |
Declares the imported iframe-resizer API. |
resources/js/common/table/useServerSort.ts |
Uses the configured pagination-key helper. |
resources/js/common/table/useServerPagination.ts |
Uses the configured pagination-key helper. |
resources/js/common/table/server-query.test.ts |
Removes legacy pagination configuration. |
resources/js/common/table/craftTable.test.ts |
Removes legacy pagination configuration. |
resources/js/common/slideouts/SlideoutPanel.vue |
Guards absent Craft configuration and updates announcement documentation. |
resources/js/common/slideouts/create-element-editor.ts |
Uses the module action-URL helper. |
resources/js/common/slideouts/create-element-editor.test.ts |
Supplies URL configuration instead of a legacy helper. |
resources/js/common/craft/pointer.ts |
Adds primary-pointer capability detection. |
resources/js/common/craft/namespace.ts |
Provides input-name and ID namespacing helpers. |
resources/js/common/craft/legacy-ui.ts |
Centralizes optional legacy markup initialization. |
resources/js/common/craft/icon-svg.ts |
Fetches and caches icon SVG markup. |
resources/js/common/craft/element-types.ts |
Reads element display names from configuration. |
resources/js/common/craft/direction.ts |
Provides direction and start-side helpers. |
resources/js/common/composables/useAsyncIcon.ts |
Uses the module SVG loader. |
resources/js/common/components/HtmlFragmentRenderer.vue |
Uses the explicit legacy-UI initializer. |
resources/js/bootstrap/seed-translations.ts |
Seeds translations before custom-element upgrades. |
resources/js/bootstrap/seed-translations.test.ts |
Covers translation seeding on import. |
resources/js/bootstrap/cp.ts |
Installs clipboard, announcements, field toggles, and event bridges. |
resources/css/fld.css |
Updates stylesheet provenance documentation. |
packages/craftcms-ui/vitest.config.ts |
Removes the relocated factory test project. |
packages/craftcms-ui/src/utilities/copy-text-prompt.ts |
Renames the prompt utility to showCopyTextPrompt. |
packages/craftcms-ui/src/index.ts |
Exports the copy-text prompt utility. |
packages/craftcms-ui/src/factory/index.ts |
Removes relocated factory exports. |
packages/craftcms-ui/src/core/element-selector/volume-folder-selector-controller.test.ts |
Uses props-only response fixtures. |
packages/craftcms-ui/src/core/element-selector/types.ts |
Removes legacy HTML from the response contract. |
packages/craftcms-ui/src/core/element-selector/element-selector-controller.test.ts |
Updates the index-body fixture. |
packages/craftcms-ui/src/core/element-selector/asset-selector-controller.test.ts |
Uses props-only response fixtures. |
packages/craftcms-ui/src/components/thumbnail-loader/README.md |
Removes the obsolete image-upload consumer. |
packages/craftcms-ui/src/components/switch/switch.ts |
Updates field-toggle integration documentation. |
packages/craftcms-ui/src/components/element-selector-modal/element-selector-modal.test.ts |
Removes obsolete HTML fixture data. |
packages/craftcms-ui/src/components/element-selector-modal/element-selector-modal.browser.test.ts |
Removes obsolete HTML fixture data. |
packages/craftcms-ui/scripts/build.js |
Stops building relocated factory modules. |
packages/craftcms-ui/package.json |
Removes relocated factory package exports. |
packages/craftcms-legacy/package.json |
Removes the obsolete font-conversion dependency. |
packages/craftcms-legacy/generalsettings/webpack.config.js |
Deletes the obsolete rebranding build. |
packages/craftcms-legacy/generalsettings/src/rebrand.scss |
Deletes legacy rebranding styles. |
packages/craftcms-legacy/generalsettings/src/rebrand.js |
Deletes legacy rebranding initialization. |
packages/craftcms-legacy/focalpoint/webpack.config.js |
Deletes the standalone focal-point build. |
packages/craftcms-legacy/cpcompat/src/element-index/ThumbsElementIndexView.js |
Preserves the relocated legacy thumbnail index view. |
packages/craftcms-legacy/cpcompat/src/element-index/index.js |
Collects adapter-owned legacy index implementations. |
packages/craftcms-legacy/cpcompat/src/element-field-settings.js |
Documents adapter-only relation settings. |
packages/craftcms-legacy/cpcompat/src/craft/Queue.js |
Registers the legacy promise queue. |
packages/craftcms-legacy/cpcompat/src/craft/index.js |
Loads legacy Craft helpers before queue registration. |
packages/craftcms-legacy/cpcompat/src/assets-field-settings.js |
Documents adapter-only asset settings. |
packages/craftcms-legacy/cpcompat/src/admin-table.js |
Documents adapter-owned legacy admin tables. |
packages/craftcms-legacy/cp/webpack.config.js |
Deletes the former core CP bundle build. |
packages/craftcms-legacy/cp/Ttf2Woff2Plugin.js |
Deletes obsolete font-conversion tooling. |
packages/craftcms-legacy/cp/src/images/view-modes/cards.svg |
Removes the legacy card-view illustration. |
packages/craftcms-legacy/cp/src/images/preview/icon-tablet.svg |
Removes the legacy tablet preview icon. |
packages/craftcms-legacy/cp/src/images/preview/icon-phone.svg |
Removes the legacy phone preview icon. |
packages/craftcms-legacy/cp/src/images/preview/chrome-tablet-top.svg |
Removes legacy tablet preview chrome. |
packages/craftcms-legacy/cp/src/images/preview/chrome-tablet-bottom.svg |
Removes legacy tablet preview chrome. |
packages/craftcms-legacy/cp/src/images/preview/chrome-phone-top.svg |
Removes legacy phone preview chrome. |
packages/craftcms-legacy/cp/src/images/preview/chrome-phone-bottom.svg |
Removes legacy phone preview chrome. |
packages/craftcms-legacy/cp/src/images/image-editor/unconstrained.svg |
Removes the legacy crop-ratio illustration. |
packages/craftcms-legacy/cp/src/images/image-editor/filters.svg |
Removes the legacy filter illustration. |
packages/craftcms-legacy/cp/src/images/image-editor/crop.svg |
Removes the legacy crop illustration. |
packages/craftcms-legacy/cp/src/images/dev-mode.svg |
Removes the legacy development-mode graphic. |
packages/craftcms-legacy/cp/src/images/content-block/inline.svg |
Removes the legacy inline-block illustration. |
packages/craftcms-legacy/cp/src/css/craft.scss |
Deletes the former legacy stylesheet entry point. |
packages/craftcms-legacy/cp/src/css/_shame.scss |
Deletes obsolete browser-specific styles. |
packages/craftcms-legacy/cp/src/css/_entry-type-select.scss |
Deletes legacy entry-type settings styles. |
packages/craftcms-legacy/cp/src/css/_debug_toolbar.scss |
Deletes the old debug-toolbar style override. |
packages/craftcms-legacy/cp/src/css/_craft-spinner.scss |
Deletes legacy spinner styles. |
packages/craftcms-legacy/cp/src/Craft.js |
Deletes the former core legacy bundle entry point. |
package.json |
Adds the directly imported iframe-resizer dependency. |
docs/messages.md |
Documents module-based notifications and adapter compatibility. |
.github/instructions/a11y.instructions.md |
Standardizes guidance on screen-reader-only text. |
Review effort: Balanced
| <div id="{{ containerId }}" class="asset-image-preview relative" | ||
| {%- if enableFocalPoint %} data-focal-point="{{ editFocal ? 'edit' : 'view' }}"{% endif %} | ||
| {%- if editFocal %} data-focal-point-toggle="{{ toggleId }}"{% endif %}> |
|
Collapsed into #20378, which carries this work plus #20320 and #20359 on a single branch rebased onto 6.x. Reviewing one branch beats keeping three bases in sync. Two commits from here were dropped as superseded by 6.x rather than carried across:
Everything else is in #20378. |

Description
Moves the legacy jQuery control panel bundle out of core, a piece at a time. Each file is ported to a TypeScript module, frozen unchanged into the Yii2 adapter, or deleted.
Craft.*stays only as backwards compatibility in the adapter, and Craft 6 APIs are exported from@craftcms/cp.Core calls modules instead of
Craft.*:Core's own markup no longer needs
Craft.initUiElements():.fieldtogglebinds itself as it's added to the page.<craft-input-date-time clearable>draws its own clear button.<craft-action-menu>, and HTTP/download actions can require an elevated session (requireElevatedSession), so core no longer renders.formsubmitmenus.Craft.ElementEditor,Craft.CPandCraft.jsmove to the adapter.Craft.ElementEditorneeded no rewrite: every element editor in core, slideouts included, is already the Vue one. The slideout bridge that ran the legacy editor could never activate (Inertia requests renderelements/Editfirst), so it's deleted.Fixed along the way:
Craft.cp.announce()said nothing on Inertia pages with nothing open.useAnnouncer()wasn't heard inside slideouts.forms.date/forms.timeblanked the value, lost the input name, and added a stray time input.pasteElements()returnedundefinedwhen nothing was copied.@/import it can't resolve.Evidence
Craft.cp.announce('Saved')on an Inertia page → console warning, nothing announced.After: the message reaches
<LiveRegion>; with a modal open, only the modal's region.<craft-switch>toggle hid its targets when switched on.After: on shows them, off hides them (
field-toggle.test.ts: fails without the fix).forms.date({name: 'd', value})posted nothing ford[date].After: posts
d[date],d[timezone],d[locale], with one clear button.6.x:@craftcms/ui, browser and unit tests pass, except one;NestedElementsIndex.test.ts › pages in read-only mode and locks the shared pager during requests. It already fails on6.x, and bisects to9c691531be.Not in this PR
Core still loads jQuery and legacy Garnish (
CpAsset); retiring those is next. The Plugin Store bundle goes in #20198.🤖 Generated with Claude Code