From 88929a219e8603fd2464b799ccb9d72863935abd Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Tue, 12 May 2026 11:51:44 +0200 Subject: [PATCH] feat: re-apply openbuilt-page-editor onto the Tier-4 shell (closes #4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grafts the never-merged #4 (feature/spec-openbuilt-page-editor) content onto the current Tier-4 manifest shell, without the competing ApplicationEditor.vue replacement / store refactor that originally blocked it. New: - src/views/PageDesigner.vue — three-pane visual manifest page designer (page list + menu tree / per-page-type sub-editor / validator panel). - src/components/page-editor/** — page-type sub-editors (index, detail, dashboard, form, logs, settings, chat, files, custom, stub), PageListEditor, MenuTreeEditor, and the fields/* builders. - src/composables/{useLivePreview,useManifestValidator,useRegisterPicker}.js - src/store/modules/applicationEditor.js — editor-local manifest state slice (Pinia; CRUD delegated to the shared object store). Wiring: - customComponents.js registers PageDesignerView. - manifest.json adds the /builder/:slug/pages page (after SchemaDesigner, before the BuilderHost wildcard). No top-level menu entry — it is a per-virtual-app sub-page like the schema designer. - ApplicationEditor.vue's Editor/History/Diff tabs are untouched. Tooling: - vuedraggable added to dependencies (used by PageListEditor/MenuTreeEditor). - eslint.config.js: no-unused-vars varsIgnorePattern now also allows leading-underscore discarded-destructure vars. - vitest.config.js: vuedraggable added to inline deps + aliased to a stub; conduction-nextcloud-vue stub gains a useAppManifest export. - tests/vitest/stubs/{nextcloud-auth,nextcloud-router,vuedraggable}.js added. Tests: PageDesigner.spec.js, page-editor component specs, composable specs, the page-designer e2e spec, and the page-editor Postman collection. Quality gates: eslint, stylelint, webpack build, and vitest (173 tests) all green. PHPCS/PHPMD/Psalm/PHPStan and PHPUnit/Newman pre-existing debt on development is untouched (this changeset is frontend-only). --- eslint.config.js | 6 +- package-lock.json | 18 +- package.json | 3 +- src/components/page-editor/ChatPageEditor.vue | 27 ++ .../page-editor/CustomPageEditor.vue | 27 ++ .../page-editor/DashboardPageEditor.vue | 78 ++++ .../page-editor/DetailPageEditor.vue | 302 ++++++++++++++ .../page-editor/FilesPageEditor.vue | 27 ++ src/components/page-editor/FormPageEditor.vue | 225 +++++++++++ .../page-editor/IndexPageEditor.vue | 241 +++++++++++ src/components/page-editor/LogsPageEditor.vue | 27 ++ src/components/page-editor/MenuTreeEditor.vue | 379 ++++++++++++++++++ src/components/page-editor/PageListEditor.vue | 312 ++++++++++++++ .../page-editor/SettingsPageEditor.vue | 27 ++ src/components/page-editor/StubPageEditor.vue | 111 +++++ .../page-editor/fields/ActionBuilder.vue | 138 +++++++ .../page-editor/fields/ColumnBuilder.vue | 173 ++++++++ .../page-editor/fields/FormFieldBuilder.vue | 148 +++++++ .../page-editor/fields/LayoutItemBuilder.vue | 153 +++++++ .../fields/SidebarSectionBuilder.vue | 117 ++++++ .../page-editor/fields/SidebarTabBuilder.vue | 136 +++++++ .../page-editor/fields/WidgetBuilder.vue | 115 ++++++ src/composables/useLivePreview.js | 69 ++++ src/composables/useManifestValidator.js | 101 +++++ src/composables/useRegisterPicker.js | 145 +++++++ src/customComponents.js | 5 + src/manifest.json | 1 + src/store/modules/applicationEditor.js | 257 ++++++++++++ src/views/PageDesigner.vue | 322 +++++++++++++++ .../page-editor/FormPageEditor.spec.js | 150 +++++++ .../page-editor/IndexPageEditor.spec.js | 185 +++++++++ .../page-editor/MenuTreeEditor.spec.js | 156 +++++++ .../page-editor/PageListEditor.spec.js | 180 +++++++++ tests/composables/useLivePreview.spec.js | 110 +++++ .../composables/useManifestValidator.spec.js | 162 ++++++++ tests/e2e/page-designer.spec.ts | 131 ++++++ ...nbuilt-page-editor.postman_collection.json | 233 +++++++++++ tests/views/PageDesigner.spec.js | 298 ++++++++++++++ .../vitest/stubs/conduction-nextcloud-vue.js | 14 + tests/vitest/stubs/nextcloud-auth.js | 13 + tests/vitest/stubs/nextcloud-router.js | 18 + tests/vitest/stubs/vuedraggable.js | 24 ++ vitest.config.js | 9 + 43 files changed, 5369 insertions(+), 4 deletions(-) create mode 100644 src/components/page-editor/ChatPageEditor.vue create mode 100644 src/components/page-editor/CustomPageEditor.vue create mode 100644 src/components/page-editor/DashboardPageEditor.vue create mode 100644 src/components/page-editor/DetailPageEditor.vue create mode 100644 src/components/page-editor/FilesPageEditor.vue create mode 100644 src/components/page-editor/FormPageEditor.vue create mode 100644 src/components/page-editor/IndexPageEditor.vue create mode 100644 src/components/page-editor/LogsPageEditor.vue create mode 100644 src/components/page-editor/MenuTreeEditor.vue create mode 100644 src/components/page-editor/PageListEditor.vue create mode 100644 src/components/page-editor/SettingsPageEditor.vue create mode 100644 src/components/page-editor/StubPageEditor.vue create mode 100644 src/components/page-editor/fields/ActionBuilder.vue create mode 100644 src/components/page-editor/fields/ColumnBuilder.vue create mode 100644 src/components/page-editor/fields/FormFieldBuilder.vue create mode 100644 src/components/page-editor/fields/LayoutItemBuilder.vue create mode 100644 src/components/page-editor/fields/SidebarSectionBuilder.vue create mode 100644 src/components/page-editor/fields/SidebarTabBuilder.vue create mode 100644 src/components/page-editor/fields/WidgetBuilder.vue create mode 100644 src/composables/useLivePreview.js create mode 100644 src/composables/useManifestValidator.js create mode 100644 src/composables/useRegisterPicker.js create mode 100644 src/store/modules/applicationEditor.js create mode 100644 src/views/PageDesigner.vue create mode 100644 tests/components/page-editor/FormPageEditor.spec.js create mode 100644 tests/components/page-editor/IndexPageEditor.spec.js create mode 100644 tests/components/page-editor/MenuTreeEditor.spec.js create mode 100644 tests/components/page-editor/PageListEditor.spec.js create mode 100644 tests/composables/useLivePreview.spec.js create mode 100644 tests/composables/useManifestValidator.spec.js create mode 100644 tests/e2e/page-designer.spec.ts create mode 100644 tests/integration/openbuilt-page-editor.postman_collection.json create mode 100644 tests/views/PageDesigner.spec.js create mode 100644 tests/vitest/stubs/nextcloud-auth.js create mode 100644 tests/vitest/stubs/nextcloud-router.js create mode 100644 tests/vitest/stubs/vuedraggable.js diff --git a/eslint.config.js b/eslint.config.js index b306f39f..ce891de1 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -31,8 +31,10 @@ module.exports = defineConfig([{ }, rules: { - // Allow unused i18n functions (t, n) — imported for future translation wiring - 'no-unused-vars': ['error', { varsIgnorePattern: '^(t|n)$', argsIgnorePattern: '^_' }], + // Allow unused i18n functions (t, n) — imported for future translation wiring. + // Also allow leading-underscore vars (idiomatic "discarded destructure" — + // `const { foo: _foo, ...rest } = x` to strip a key while keeping the rest). + 'no-unused-vars': ['error', { varsIgnorePattern: '^(t|n|_)', argsIgnorePattern: '^_' }], 'jsdoc/require-jsdoc': 'off', 'vue/first-attribute-linebreak': 'off', '@typescript-eslint/no-explicit-any': 'off', diff --git a/package-lock.json b/package-lock.json index 97b53ff3..c5453ebd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,8 @@ "pinia": "^2.1.7", "vue": "^2.7.14", "vue-material-design-icons": "^5.3.0", - "vue-router": "^3.6.5" + "vue-router": "^3.6.5", + "vuedraggable": "^2.24.3" }, "devDependencies": { "@cyclonedx/cyclonedx-npm": "^4.2.1", @@ -19048,6 +19049,12 @@ "node": ">= 14" } }, + "node_modules/sortablejs": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz", + "integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==", + "license": "MIT" + }, "node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", @@ -22926,6 +22933,15 @@ "vue": "^2.5.0" } }, + "node_modules/vuedraggable": { + "version": "2.24.3", + "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz", + "integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==", + "license": "MIT", + "dependencies": { + "sortablejs": "1.10.2" + } + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", diff --git a/package.json b/package.json index 5c0aef37..f7776e38 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "pinia": "^2.1.7", "vue": "^2.7.14", "vue-material-design-icons": "^5.3.0", - "vue-router": "^3.6.5" + "vue-router": "^3.6.5", + "vuedraggable": "^2.24.3" }, "overrides": { "libxmljs2": "^0.37.0" diff --git a/src/components/page-editor/ChatPageEditor.vue b/src/components/page-editor/ChatPageEditor.vue new file mode 100644 index 00000000..64919bcb --- /dev/null +++ b/src/components/page-editor/ChatPageEditor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/page-editor/CustomPageEditor.vue b/src/components/page-editor/CustomPageEditor.vue new file mode 100644 index 00000000..bddce65a --- /dev/null +++ b/src/components/page-editor/CustomPageEditor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/page-editor/DashboardPageEditor.vue b/src/components/page-editor/DashboardPageEditor.vue new file mode 100644 index 00000000..7ee6f86b --- /dev/null +++ b/src/components/page-editor/DashboardPageEditor.vue @@ -0,0 +1,78 @@ + + + + + + + diff --git a/src/components/page-editor/DetailPageEditor.vue b/src/components/page-editor/DetailPageEditor.vue new file mode 100644 index 00000000..bceb2dae --- /dev/null +++ b/src/components/page-editor/DetailPageEditor.vue @@ -0,0 +1,302 @@ + + + + + + + diff --git a/src/components/page-editor/FilesPageEditor.vue b/src/components/page-editor/FilesPageEditor.vue new file mode 100644 index 00000000..b09ad765 --- /dev/null +++ b/src/components/page-editor/FilesPageEditor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/page-editor/FormPageEditor.vue b/src/components/page-editor/FormPageEditor.vue new file mode 100644 index 00000000..0045659d --- /dev/null +++ b/src/components/page-editor/FormPageEditor.vue @@ -0,0 +1,225 @@ + + + + + + + diff --git a/src/components/page-editor/IndexPageEditor.vue b/src/components/page-editor/IndexPageEditor.vue new file mode 100644 index 00000000..9e51740d --- /dev/null +++ b/src/components/page-editor/IndexPageEditor.vue @@ -0,0 +1,241 @@ + + + + + + + diff --git a/src/components/page-editor/LogsPageEditor.vue b/src/components/page-editor/LogsPageEditor.vue new file mode 100644 index 00000000..7d6913c2 --- /dev/null +++ b/src/components/page-editor/LogsPageEditor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/page-editor/MenuTreeEditor.vue b/src/components/page-editor/MenuTreeEditor.vue new file mode 100644 index 00000000..733c929a --- /dev/null +++ b/src/components/page-editor/MenuTreeEditor.vue @@ -0,0 +1,379 @@ + + + + + + + diff --git a/src/components/page-editor/PageListEditor.vue b/src/components/page-editor/PageListEditor.vue new file mode 100644 index 00000000..c03fdfb6 --- /dev/null +++ b/src/components/page-editor/PageListEditor.vue @@ -0,0 +1,312 @@ + + + + + + + diff --git a/src/components/page-editor/SettingsPageEditor.vue b/src/components/page-editor/SettingsPageEditor.vue new file mode 100644 index 00000000..22ff455b --- /dev/null +++ b/src/components/page-editor/SettingsPageEditor.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/page-editor/StubPageEditor.vue b/src/components/page-editor/StubPageEditor.vue new file mode 100644 index 00000000..d6b50b90 --- /dev/null +++ b/src/components/page-editor/StubPageEditor.vue @@ -0,0 +1,111 @@ + + +