From c71af071631e08bb592b7f1a9899ee6b79e720d9 Mon Sep 17 00:00:00 2001 From: Tomas Vondracek Date: Sun, 25 Oct 2026 10:08:43 +0100 Subject: [PATCH] feat: migrate admin assets to Vue 3 Composition API and TypeScript --- assets/js/app/common.js | 5 +- assets/js/app/editor/Components/Checkbox.vue | 50 +- .../js/app/editor/Components/Collection.vue | 436 +- assets/js/app/editor/Components/Date.vue | 202 +- assets/js/app/editor/Components/Email.vue | 45 +- assets/js/app/editor/Components/Embed.vue | 203 +- assets/js/app/editor/Components/File.vue | 496 +- assets/js/app/editor/Components/Filelist.vue | 227 +- assets/js/app/editor/Components/Html.vue | 67 +- assets/js/app/editor/Components/Image.vue | 670 +- assets/js/app/editor/Components/Imagelist.vue | 297 +- assets/js/app/editor/Components/Language.vue | 92 +- assets/js/app/editor/Components/Markdown.vue | 85 +- assets/js/app/editor/Components/Number.vue | 46 +- assets/js/app/editor/Components/Password.vue | 128 +- .../js/app/editor/Components/ProgressBar.vue | 44 +- assets/js/app/editor/Components/Select.vue | 454 +- assets/js/app/editor/Components/Slug.vue | 201 +- assets/js/app/editor/Components/Text.vue | 90 +- assets/js/app/editor/Components/Textarea.vue | 56 +- .../js/app/editor/Components/ThemeSelect.vue | 50 +- .../app/editor/composables/useFieldValue.ts | 39 + assets/js/app/editor/index.js | 59 - assets/js/app/editor/index.ts | 59 + assets/js/app/editor/mixins/value.js | 16 - assets/js/app/editor/store/index.js | 11 - .../editor/store/modules/general/_actions.js | 7 - .../editor/store/modules/general/_getters.js | 5 - .../store/modules/general/_mutations.js | 7 - .../editor/store/modules/general/_state.js | 5 - .../app/editor/store/modules/general/index.js | 12 - assets/js/app/editor/types.ts | 18 + .../js/app/editor/utils/serverFileBrowser.ts | 217 + assets/js/app/editor/utils/upload.ts | 19 + assets/js/app/eventBus.ts | 8 + assets/js/app/{index.js => index.ts} | 0 assets/js/app/listing/Components/Filter.vue | 77 +- assets/js/app/listing/Components/Records.vue | 32 +- .../js/app/listing/Components/SelectBox.vue | 118 +- .../listing/Components/Table/Row/_Actions.vue | 89 +- .../Components/Table/Row/_Checkbox.vue | 68 +- .../listing/Components/Table/Row/_Meta.vue | 28 +- .../listing/Components/Table/Row/_Sorting.vue | 15 +- .../listing/Components/Table/Row/index.vue | 104 +- .../js/app/listing/Components/Table/index.vue | 45 +- assets/js/app/listing/index.js | 31 - assets/js/app/listing/index.ts | 31 + assets/js/app/listing/mixins/type.js | 7 - assets/js/app/listing/store/index.js | 18 - assets/js/app/listing/store/index.ts | 52 + .../listing/store/modules/general/_actions.js | 13 - .../listing/store/modules/general/_getters.js | 7 - .../store/modules/general/_mutations.js | 13 - .../listing/store/modules/general/_state.js | 7 - .../listing/store/modules/general/index.js | 12 - .../listing/store/modules/listing/_actions.js | 7 - .../listing/store/modules/listing/_getters.js | 10 - .../store/modules/listing/_mutations.js | 7 - .../listing/store/modules/listing/_state.js | 5 - .../listing/store/modules/listing/index.js | 12 - .../store/modules/selecting/_actions.js | 13 - .../store/modules/selecting/_getters.js | 7 - .../store/modules/selecting/_mutations.js | 16 - .../listing/store/modules/selecting/_state.js | 7 - .../listing/store/modules/selecting/index.js | 12 - .../listing/store/modules/type/_actions.js | 7 - .../listing/store/modules/type/_getters.js | 5 - .../listing/store/modules/type/_mutations.js | 7 - .../app/listing/store/modules/type/_state.js | 5 - .../app/listing/store/modules/type/index.js | 12 - assets/js/app/listing/types.ts | 40 + assets/js/app/login/index.js | 19 +- assets/js/app/modal.d.ts | 1 + assets/js/app/modal.js | 2 +- assets/js/app/notifications/index.js | 4 +- assets/js/app/patience-is-a-virtue.d.ts | 2 + .../app/sidebar/Components/Menu/_SubMenu.vue | 17 +- .../js/app/sidebar/Components/Menu/index.vue | 36 +- assets/js/app/sidebar/Components/Sidebar.vue | 44 +- .../sidebar/Components/_SidebarToggler.vue | 58 +- assets/js/app/sidebar/index.js | 16 - assets/js/app/sidebar/index.ts | 19 + assets/js/app/sidebar/store/index.js | 11 - assets/js/app/sidebar/store/index.ts | 11 + .../sidebar/store/modules/general/_actions.js | 7 - .../sidebar/store/modules/general/_getters.js | 5 - .../store/modules/general/_mutations.js | 7 - .../sidebar/store/modules/general/_state.js | 5 - .../sidebar/store/modules/general/index.js | 12 - assets/js/app/sidebar/types.ts | 17 + assets/js/app/toolbar/Components/Toolbar.vue | 67 +- assets/js/app/toolbar/index.js | 25 - assets/js/app/toolbar/index.ts | 25 + assets/js/app/toolbar/store/index.js | 11 - assets/js/app/toolbar/store/index.ts | 11 + .../toolbar/store/modules/general/_actions.js | 7 - .../toolbar/store/modules/general/_getters.js | 5 - .../store/modules/general/_mutations.js | 7 - .../toolbar/store/modules/general/_state.js | 5 - .../toolbar/store/modules/general/index.js | 12 - assets/js/app/utils/debounce.ts | 27 + assets/js/{bolt.js => bolt.ts} | 0 assets/js/shims-vue.d.ts | 86 + config/bolt/contenttypes.yaml | 1 - config/packages/assets.yaml | 7 + eslint.config.mjs | 63 +- package-lock.json | 17281 +++++++++------- package.json | 72 +- .../Backend/ClearCacheController.php | 4 +- .../Backend/ExtensionsController.php | 4 +- templates/_partials/fields/date.html.twig | 2 +- templates/_partials/fields/markdown.html.twig | 2 +- tests/unit/README.md | 74 +- tests/unit/app/ajax-save.spec.ts | 6 +- tests/unit/app/common.spec.ts | 9 +- tests/unit/app/notifications.spec.ts | 4 +- tests/unit/components/Checkbox.spec.ts | 19 +- tests/unit/components/Collection.spec.ts | 67 +- tests/unit/components/Date.spec.ts | 72 +- tests/unit/components/Email.spec.ts | 8 +- tests/unit/components/Embed.spec.ts | 4 +- tests/unit/components/File.spec.ts | 101 +- tests/unit/components/Filelist.spec.ts | 28 +- tests/unit/components/Html.spec.ts | 8 +- tests/unit/components/Image.spec.ts | 281 +- tests/unit/components/Imagelist.spec.ts | 35 +- tests/unit/components/Language.spec.ts | 11 +- tests/unit/components/Markdown.spec.ts | 117 +- tests/unit/components/Number.spec.ts | 8 +- tests/unit/components/Password.spec.ts | 2 +- tests/unit/components/ProgressBar.spec.ts | 6 +- tests/unit/components/Select.spec.ts | 91 +- tests/unit/components/Slug.spec.ts | 65 +- .../components/SlugTextIntegration.spec.ts | 71 + tests/unit/components/Text.spec.ts | 74 +- tests/unit/components/Textarea.spec.ts | 12 +- tests/unit/components/ThemeSelect.spec.ts | 23 +- tests/unit/components/listing/Filter.spec.ts | 56 +- tests/unit/components/listing/Records.spec.ts | 27 +- tests/unit/components/listing/Row.spec.ts | 58 +- .../components/listing/RowActions.spec.ts | 13 +- .../components/listing/RowCheckbox.spec.ts | 63 +- tests/unit/components/listing/RowMeta.spec.ts | 12 +- .../components/listing/RowSorting.spec.ts | 2 +- .../unit/components/listing/SelectBox.spec.ts | 50 +- tests/unit/components/listing/Table.spec.ts | 27 +- tests/unit/components/sidebar/Menu.spec.ts | 12 +- tests/unit/components/sidebar/Sidebar.spec.ts | 39 +- .../components/sidebar/SidebarToggler.spec.ts | 22 +- tests/unit/components/sidebar/SubMenu.spec.ts | 28 +- tests/unit/components/toolbar/Toolbar.spec.ts | 81 +- tests/unit/composables/useFieldValue.spec.ts | 70 + tests/unit/helpers/async.ts | 10 - tests/unit/helpers/bus.ts | 31 +- tests/unit/helpers/errors.ts | 21 +- tests/unit/helpers/jquery.ts | 16 + tests/unit/helpers/store.ts | 153 +- tests/unit/helpers/stubs.ts | 105 +- tests/unit/helpers/warnings.ts | 22 +- tests/unit/mixins/type.spec.ts | 40 - tests/unit/mixins/value.spec.ts | 94 - tests/unit/setup.ts | 14 +- tests/unit/shims-vue.d.ts | 24 - tests/unit/shims-vuex.d.ts | 17 - tests/unit/store/listing.spec.ts | 132 +- tests/unit/store/sidebar-toolbar.spec.ts | 40 +- tests/unit/utils/serverFileBrowser.spec.ts | 197 + tsconfig.json | 12 +- vitest.config.ts | 59 +- webpack.config.js => webpack.config.mjs | 27 +- 170 files changed, 14703 insertions(+), 11449 deletions(-) create mode 100644 assets/js/app/editor/composables/useFieldValue.ts delete mode 100644 assets/js/app/editor/index.js create mode 100644 assets/js/app/editor/index.ts delete mode 100644 assets/js/app/editor/mixins/value.js delete mode 100644 assets/js/app/editor/store/index.js delete mode 100644 assets/js/app/editor/store/modules/general/_actions.js delete mode 100644 assets/js/app/editor/store/modules/general/_getters.js delete mode 100644 assets/js/app/editor/store/modules/general/_mutations.js delete mode 100644 assets/js/app/editor/store/modules/general/_state.js delete mode 100644 assets/js/app/editor/store/modules/general/index.js create mode 100644 assets/js/app/editor/types.ts create mode 100644 assets/js/app/editor/utils/serverFileBrowser.ts create mode 100644 assets/js/app/editor/utils/upload.ts create mode 100644 assets/js/app/eventBus.ts rename assets/js/app/{index.js => index.ts} (100%) delete mode 100644 assets/js/app/listing/index.js create mode 100644 assets/js/app/listing/index.ts delete mode 100644 assets/js/app/listing/mixins/type.js delete mode 100644 assets/js/app/listing/store/index.js create mode 100644 assets/js/app/listing/store/index.ts delete mode 100644 assets/js/app/listing/store/modules/general/_actions.js delete mode 100644 assets/js/app/listing/store/modules/general/_getters.js delete mode 100644 assets/js/app/listing/store/modules/general/_mutations.js delete mode 100644 assets/js/app/listing/store/modules/general/_state.js delete mode 100644 assets/js/app/listing/store/modules/general/index.js delete mode 100644 assets/js/app/listing/store/modules/listing/_actions.js delete mode 100644 assets/js/app/listing/store/modules/listing/_getters.js delete mode 100644 assets/js/app/listing/store/modules/listing/_mutations.js delete mode 100644 assets/js/app/listing/store/modules/listing/_state.js delete mode 100644 assets/js/app/listing/store/modules/listing/index.js delete mode 100644 assets/js/app/listing/store/modules/selecting/_actions.js delete mode 100644 assets/js/app/listing/store/modules/selecting/_getters.js delete mode 100644 assets/js/app/listing/store/modules/selecting/_mutations.js delete mode 100644 assets/js/app/listing/store/modules/selecting/_state.js delete mode 100644 assets/js/app/listing/store/modules/selecting/index.js delete mode 100644 assets/js/app/listing/store/modules/type/_actions.js delete mode 100644 assets/js/app/listing/store/modules/type/_getters.js delete mode 100644 assets/js/app/listing/store/modules/type/_mutations.js delete mode 100644 assets/js/app/listing/store/modules/type/_state.js delete mode 100644 assets/js/app/listing/store/modules/type/index.js create mode 100644 assets/js/app/listing/types.ts create mode 100644 assets/js/app/modal.d.ts create mode 100644 assets/js/app/patience-is-a-virtue.d.ts delete mode 100644 assets/js/app/sidebar/index.js create mode 100644 assets/js/app/sidebar/index.ts delete mode 100644 assets/js/app/sidebar/store/index.js create mode 100644 assets/js/app/sidebar/store/index.ts delete mode 100644 assets/js/app/sidebar/store/modules/general/_actions.js delete mode 100644 assets/js/app/sidebar/store/modules/general/_getters.js delete mode 100644 assets/js/app/sidebar/store/modules/general/_mutations.js delete mode 100644 assets/js/app/sidebar/store/modules/general/_state.js delete mode 100644 assets/js/app/sidebar/store/modules/general/index.js create mode 100644 assets/js/app/sidebar/types.ts delete mode 100644 assets/js/app/toolbar/index.js create mode 100644 assets/js/app/toolbar/index.ts delete mode 100644 assets/js/app/toolbar/store/index.js create mode 100644 assets/js/app/toolbar/store/index.ts delete mode 100644 assets/js/app/toolbar/store/modules/general/_actions.js delete mode 100644 assets/js/app/toolbar/store/modules/general/_getters.js delete mode 100644 assets/js/app/toolbar/store/modules/general/_mutations.js delete mode 100644 assets/js/app/toolbar/store/modules/general/_state.js delete mode 100644 assets/js/app/toolbar/store/modules/general/index.js create mode 100644 assets/js/app/utils/debounce.ts rename assets/js/{bolt.js => bolt.ts} (100%) create mode 100644 assets/js/shims-vue.d.ts create mode 100644 tests/unit/components/SlugTextIntegration.spec.ts create mode 100644 tests/unit/composables/useFieldValue.spec.ts delete mode 100644 tests/unit/helpers/async.ts create mode 100644 tests/unit/helpers/jquery.ts delete mode 100644 tests/unit/mixins/type.spec.ts delete mode 100644 tests/unit/mixins/value.spec.ts delete mode 100644 tests/unit/shims-vue.d.ts delete mode 100644 tests/unit/shims-vuex.d.ts create mode 100644 tests/unit/utils/serverFileBrowser.spec.ts rename webpack.config.js => webpack.config.mjs (69%) diff --git a/assets/js/app/common.js b/assets/js/app/common.js index 8523ef607f..fdb7110fb2 100644 --- a/assets/js/app/common.js +++ b/assets/js/app/common.js @@ -144,7 +144,10 @@ $(document).ready(function () { /* ** Copy text to clipboard. Used in filemanager actions. */ - new ClipboardJS('*[data-clipboard-text]'); + const clipboard = new ClipboardJS('*[data-clipboard-text]'); + clipboard.on('success', function (event) { + event.clearSelection(); + }); /* End of copy text to clipboard */ /* diff --git a/assets/js/app/editor/Components/Checkbox.vue b/assets/js/app/editor/Components/Checkbox.vue index d507424c84..1f82e07f51 100644 --- a/assets/js/app/editor/Components/Checkbox.vue +++ b/assets/js/app/editor/Components/Checkbox.vue @@ -8,9 +8,9 @@ :checked="value" type="checkbox" :readonly="readonly" - @change="liveValue = $event.target.checked" + @change="liveValue = ($event.target as HTMLInputElement).checked" /> - + @@ -19,36 +19,18 @@ - diff --git a/assets/js/app/editor/Components/Collection.vue b/assets/js/app/editor/Components/Collection.vue index 2e19a10d3f..17cc7af3a8 100644 --- a/assets/js/app/editor/Components/Collection.vue +++ b/assets/js/app/editor/Components/Collection.vue @@ -1,7 +1,7 @@ - diff --git a/assets/js/app/editor/Components/Date.vue b/assets/js/app/editor/Components/Date.vue index 5a9e184d24..3c3bf41fde 100644 --- a/assets/js/app/editor/Components/Date.vue +++ b/assets/js/app/editor/Components/Date.vue @@ -1,5 +1,5 @@ - diff --git a/assets/js/app/editor/Components/Email.vue b/assets/js/app/editor/Components/Email.vue index 6a9f887912..f23b26d9e3 100644 --- a/assets/js/app/editor/Components/Email.vue +++ b/assets/js/app/editor/Components/Email.vue @@ -10,40 +10,23 @@ type="email" :required="required" :readonly="readonly" - :data-errormessage="errormessage" - :pattern="pattern" - :placeholder="placeholder" + :data-errormessage="typeof errormessage === 'string' ? errormessage : undefined" + :pattern="typeof pattern === 'string' ? pattern : undefined" + :placeholder="typeof placeholder === 'string' ? placeholder : undefined" /> - diff --git a/assets/js/app/editor/Components/Embed.vue b/assets/js/app/editor/Components/Embed.vue index eb9bd8d44b..8ad01e84f0 100644 --- a/assets/js/app/editor/Components/Embed.vue +++ b/assets/js/app/editor/Components/Embed.vue @@ -8,6 +8,7 @@
- + {{ labels.label_matched_embed }}
- + {{ labels.label_preview }}
@@ -108,102 +114,95 @@ - diff --git a/assets/js/app/editor/Components/File.vue b/assets/js/app/editor/Components/File.vue index e6435a3015..33d4911888 100644 --- a/assets/js/app/editor/Components/File.vue +++ b/assets/js/app/editor/Components/File.vue @@ -10,6 +10,7 @@
@@ -132,129 +135,155 @@ - diff --git a/assets/js/app/editor/Components/Filelist.vue b/assets/js/app/editor/Components/Filelist.vue index 6411abbe72..8f012a6023 100644 --- a/assets/js/app/editor/Components/Filelist.vue +++ b/assets/js/app/editor/Components/Filelist.vue @@ -10,10 +10,10 @@ :directory="directory" :filelist="filelist" :csrf-token="csrfToken" - :labels="labels" + :labels="labelsValue" :in-filelist="true" :name="fieldName(index)" - :extensions="extensions" + :extensions="extensionsValue" :is-first-in-filelist="isFirstInFilelist(index)" :is-last-in-filelist="isLastInFilelist(index)" :readonly="readonly" @@ -28,105 +28,136 @@ - diff --git a/assets/js/app/editor/Components/Html.vue b/assets/js/app/editor/Components/Html.vue index a17e5c85b0..0ff92cccdd 100644 --- a/assets/js/app/editor/Components/Html.vue +++ b/assets/js/app/editor/Components/Html.vue @@ -1,47 +1,38 @@ - diff --git a/assets/js/app/editor/Components/Image.vue b/assets/js/app/editor/Components/Image.vue index 5bd15cee04..5f9a22ff6c 100644 --- a/assets/js/app/editor/Components/Image.vue +++ b/assets/js/app/editor/Components/Image.vue @@ -9,7 +9,7 @@
- +
- +
- {{ labels.button_remove }} + + {{ labels.button_remove }}
@@ -185,137 +189,173 @@ tabindex="-1" type="file" :accept="acceptedExtensions" - @change="uploadFile($event.target.files[0])" + @change="uploadSelectedFile" />
- diff --git a/assets/js/app/editor/Components/Imagelist.vue b/assets/js/app/editor/Components/Imagelist.vue index 8e7e57875b..9e344a7a31 100644 --- a/assets/js/app/editor/Components/Imagelist.vue +++ b/assets/js/app/editor/Components/Imagelist.vue @@ -1,8 +1,7 @@ - diff --git a/assets/js/app/editor/Components/Language.vue b/assets/js/app/editor/Components/Language.vue index 9b0f136d84..2f2f910052 100644 --- a/assets/js/app/editor/Components/Language.vue +++ b/assets/js/app/editor/Components/Language.vue @@ -1,69 +1,77 @@