Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

Commit e12b3ed

Browse files
committed
feat: re-apply openbuilt-page-editor onto the Tier-4 shell (closes #4)
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).
1 parent 3a071f2 commit e12b3ed

43 files changed

Lines changed: 5369 additions & 4 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

eslint.config.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ module.exports = defineConfig([{
3131
},
3232

3333
rules: {
34-
// Allow unused i18n functions (t, n) — imported for future translation wiring
35-
'no-unused-vars': ['error', { varsIgnorePattern: '^(t|n)$', argsIgnorePattern: '^_' }],
34+
// Allow unused i18n functions (t, n) — imported for future translation wiring.
35+
// Also allow leading-underscore vars (idiomatic "discarded destructure" —
36+
// `const { foo: _foo, ...rest } = x` to strip a key while keeping the rest).
37+
'no-unused-vars': ['error', { varsIgnorePattern: '^(t|n|_)', argsIgnorePattern: '^_' }],
3638
'jsdoc/require-jsdoc': 'off',
3739
'vue/first-attribute-linebreak': 'off',
3840
'@typescript-eslint/no-explicit-any': 'off',

package-lock.json

Lines changed: 17 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"pinia": "^2.1.7",
4040
"vue": "^2.7.14",
4141
"vue-material-design-icons": "^5.3.0",
42-
"vue-router": "^3.6.5"
42+
"vue-router": "^3.6.5",
43+
"vuedraggable": "^2.24.3"
4344
},
4445
"overrides": {
4546
"libxmljs2": "^0.37.0"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!-- SPDX-License-Identifier: EUPL-1.2 -->
2+
<!--
3+
- ChatPageEditor — v1.1 stub. Task 4.6 deferred.
4+
-->
5+
<template>
6+
<StubPageEditor
7+
:title="t('openbuilt', 'Chat page')"
8+
:message="t('openbuilt', 'Structured chat editor (conversationSource OR postUrl one-of plus optional schema) coming in v1.1. For now, edit the raw JSON below or use the Raw JSON tab.')"
9+
:config="config"
10+
@update:config="$emit('update:config', $event)" />
11+
</template>
12+
13+
<script>
14+
import StubPageEditor from './StubPageEditor.vue'
15+
16+
export default {
17+
name: 'ChatPageEditor',
18+
components: { StubPageEditor },
19+
props: {
20+
config: {
21+
type: Object,
22+
default: () => ({}),
23+
},
24+
},
25+
emits: ['update:config'],
26+
}
27+
</script>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!-- SPDX-License-Identifier: EUPL-1.2 -->
2+
<!--
3+
- CustomPageEditor — v1.1 stub. Task 4.9 deferred.
4+
-->
5+
<template>
6+
<StubPageEditor
7+
:title="t('openbuilt', 'Custom page')"
8+
:message="t('openbuilt', 'Structured custom-page editor (customComponents registry picker + free-form config) coming in v1.1. For now, edit the raw JSON below or use the Raw JSON tab.')"
9+
:config="config"
10+
@update:config="$emit('update:config', $event)" />
11+
</template>
12+
13+
<script>
14+
import StubPageEditor from './StubPageEditor.vue'
15+
16+
export default {
17+
name: 'CustomPageEditor',
18+
components: { StubPageEditor },
19+
props: {
20+
config: {
21+
type: Object,
22+
default: () => ({}),
23+
},
24+
},
25+
emits: ['update:config'],
26+
}
27+
</script>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!-- SPDX-License-Identifier: EUPL-1.2 -->
2+
<!--
3+
- DashboardPageEditor — widgets list + layout grid editor. Reuses
4+
- WidgetBuilder.vue + LayoutItemBuilder.vue.
5+
-->
6+
<template>
7+
<div class="dashboard-page-editor">
8+
<h3 class="dashboard-page-editor__title">
9+
{{ t('openbuilt', 'Dashboard page') }}
10+
</h3>
11+
12+
<fieldset class="dashboard-page-editor__fieldset">
13+
<legend>{{ t('openbuilt', 'Widgets') }}</legend>
14+
<WidgetBuilder
15+
:model-value="config.widgets || []"
16+
@update:modelValue="update('widgets', $event)" />
17+
</fieldset>
18+
19+
<fieldset class="dashboard-page-editor__fieldset">
20+
<legend>{{ t('openbuilt', 'Layout') }}</legend>
21+
<LayoutItemBuilder
22+
:model-value="config.layout || []"
23+
@update:modelValue="update('layout', $event)" />
24+
</fieldset>
25+
</div>
26+
</template>
27+
28+
<script>
29+
import WidgetBuilder from './fields/WidgetBuilder.vue'
30+
import LayoutItemBuilder from './fields/LayoutItemBuilder.vue'
31+
32+
export default {
33+
name: 'DashboardPageEditor',
34+
components: { WidgetBuilder, LayoutItemBuilder },
35+
props: {
36+
config: {
37+
type: Object,
38+
default: () => ({}),
39+
},
40+
},
41+
emits: ['update:config'],
42+
methods: {
43+
update(key, value) {
44+
const next = { ...this.config }
45+
if (!value || (Array.isArray(value) && value.length === 0)) {
46+
delete next[key]
47+
} else {
48+
next[key] = value
49+
}
50+
this.$emit('update:config', next)
51+
},
52+
},
53+
}
54+
</script>
55+
56+
<style scoped>
57+
.dashboard-page-editor {
58+
display: flex;
59+
flex-direction: column;
60+
gap: 12px;
61+
padding: 12px;
62+
}
63+
.dashboard-page-editor__title {
64+
margin: 0;
65+
font-size: 16px;
66+
font-weight: 600;
67+
}
68+
.dashboard-page-editor__fieldset {
69+
border: 1px solid var(--color-border);
70+
border-radius: var(--border-radius);
71+
padding: 8px;
72+
}
73+
.dashboard-page-editor__fieldset legend {
74+
padding: 0 6px;
75+
font-weight: 600;
76+
font-size: 13px;
77+
}
78+
</style>

0 commit comments

Comments
 (0)