diff --git a/appinfo/info.xml b/appinfo/info.xml
index d841966..7ce67a4 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -22,7 +22,7 @@ Vrij en open source onder de EUPL-1.2-licentie.
**Ondersteuning:** Voor ondersteuning, neem contact op via support@conduction.nl.
]]>
- 0.3.7
+ 0.3.8
agpl
Conduction
OpenBuilt
diff --git a/src/App.vue b/src/App.vue
index dbbca09..b98f9ca 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,21 +1,22 @@
@@ -74,12 +75,16 @@ export default {
required: true,
},
/**
- * Registry of consumer-injected components used by `type: "custom"`
- * pages (`page.component`) and other manifest slot overrides.
+ * V2 kind-tagged registry (ADR-036) — map of registry key →
+ * `{ kind: "page", component }`. CnPageRenderer resolves every
+ * manifest-referenced component name (type:"custom" pages,
+ * cardComponent, headerComponent, actionsComponent,
+ * sidebarTabs[].component) against the `kind: "page"` entries here.
+ * Replaces the deprecated `customComponents` prop.
*
* @type {object}
*/
- customComponents: {
+ registry: {
type: Object,
default: () => ({}),
},
@@ -93,18 +98,6 @@ export default {
type: Object,
default: null,
},
- /**
- * v2 component registry — map of registry key → `{ kind, component, ...metadata }`.
- * Passed to CnAppRoot which validates kinds at mounted() time and provides the
- * map to descendants via `cnRegistry`. Resolves type:"custom" page components,
- * modals, and future widget/form-field/cell-renderer entries.
- *
- * @type {object}
- */
- registry: {
- type: Object,
- default: () => ({}),
- },
},
computed: {
diff --git a/src/customComponents.js b/src/customComponents.js
deleted file mode 100644
index 05c9aec..0000000
--- a/src/customComponents.js
+++ /dev/null
@@ -1,89 +0,0 @@
-// SPDX-License-Identifier: EUPL-1.2
-//
-// Custom-component registry for OpenBuilt's manifest-driven app shell.
-//
-// Most of OpenBuilt's surfaces are now built-in manifest page types — the
-// Dashboard is `type: "dashboard"` and the Virtual apps list/detail are
-// `type: "index"` / `type: "detail"` (with custom cards, sidebar tabs and an
-// actions bar resolved from this registry). The remaining `type: "custom"`
-// pages are the tooling UIs that have no generic CRUD equivalent (schema
-// designer, page designer, export-jobs list, virtual-app host).
-// Keep this file SHORT — adding entries should be a deliberate decision;
-// moving a page onto a built-in manifest type is the right direction.
-//
-// Resolution order at runtime (CnPageRenderer):
-// 1. Built-in page types (CnIndexPage, CnDetailPage, CnDashboardPage, …)
-// 2. Built-in widget types (data, metadata, audit-trail, version-info, …)
-// 3. customComponents (this file) ← consumer-injected components
-// (also resolves `pages[].config.cardComponent`, `…sidebarTabs[].component`
-// and `…actionsComponent`).
-//
-// See ADR-024 (app manifest) and docs/migrating-to-manifest.md in
-// @conduction/nextcloud-vue.
-
-// Virtual apps — index card + detail sidebar tabs + detail actions.
-import ApplicationCard from './components/ApplicationCard.vue'
-import ApplicationManifestTab from './components/tabs/ApplicationManifestTab.vue'
-import ApplicationVersionsTab from './components/tabs/ApplicationVersionsTab.vue'
-import ApplicationDiffTab from './components/tabs/ApplicationDiffTab.vue'
-import ApplicationIconTab from './components/tabs/ApplicationIconTab.vue'
-import ApplicationDetailActions from './components/ApplicationDetailActions.vue'
-// Maintainer-dashboard main area for VirtualAppDetail
-// (openbuilt-app-detail-overview REQ-OBADO-001) — replaces the
-// generic CnDetailPage data widget. Owns hero strip + version pill
-// tabs + window toggle + KPI grid + activity chart + structural
-// widgets. Registered as the page entry's `headerComponent` in
-// src/manifest.json.
-import ApplicationDetailHeader from './components/applicationDetail/ApplicationDetailHeader.vue'
-// Virtual apps index "Add application" actions bar — opens the four-step
-// creation wizard (openbuilt-app-creation-wizard REQ-OBWIZ-001).
-// Referenced by the VirtualApps page's config.actionsComponent.
-import VirtualAppsActions from './components/VirtualAppsActions.vue'
-// Tooling pages that stay `type: "custom"`.
-import SchemaDesignerView from './views/SchemaDesigner.vue'
-import PageDesignerView from './views/PageDesignerHost.vue'
-import BuilderHostView from './views/BuilderHost.vue'
-// Features & Roadmap page — thin wrapper around the lib's
-// CnFeaturesAndRoadmapView (in-product roadmap surface powered by
-// OpenRegister's github-issue-proxy). See ConductionNL/hydra#251.
-
-export default {
- // VirtualApps (`type: index`) card — name, status pill, version, "live"
- // marker, caller's role; click navigates to VirtualAppDetail.
- ApplicationCard,
- // VirtualAppDetail (`type: detail`) sidebar tabs: raw-JSON manifest
- // editor (the visual designer lives at /builder/:slug/pages), version
- // history (+ rollback), the manifest diff, and icon upload/preview.
- ApplicationManifestTab,
- ApplicationVersionsTab,
- ApplicationDiffTab,
- ApplicationIconTab,
- // VirtualApps index actions bar — "Add application" button that opens the
- // four-step CreateApplicationWizard (openbuilt-app-creation-wizard).
- VirtualAppsActions,
- // VirtualAppDetail actions bar — Publish (OR lifecycle transition),
- // Manage permissions (PermissionsModal, ADR-004 modal isolation),
- // Design pages, Open virtual app.
- ApplicationDetailActions,
- // VirtualAppDetail headerComponent (openbuilt-app-detail-overview
- // REQ-OBADO-001 / REQ-OBADO-011) — purpose-built maintainer
- // dashboard replacing the generic main-area data widget.
- ApplicationDetailHeader,
- // Visual schema designer for a virtual app's register
- // (/builder/:slug/schemas[/:schemaId] and the paramless /schemas
- // shortcut, which defaults to the hello-world seed app).
- SchemaDesignerView,
- // Visual manifest page designer for a virtual app
- // (/builder/:slug/pages) — PageDesignerHost loads the app's manifest,
- // hands it to the controlled PageDesigner (three-pane page-list /
- // per-type sub-editor / validator side-panel, REQ-OBPD-003), and
- // persists edits back.
- PageDesignerView,
- // Export-jobs list — status of Phase-2 "export to real app" runs.
- // Virtual-app host — mounts a nested CnAppRoot rendering the virtual
- // app's manifest from GET /api/applications/{slug}/manifest.
- BuilderHostView,
- // Template gallery — browse seeded ApplicationTemplate records and
- // clone one into a new virtual app (openbuilt-templates-marketplace).
- // Features & Roadmap page (lib's CnFeaturesAndRoadmapView).
-}
diff --git a/src/main.js b/src/main.js
index 431b6bb..155bb06 100644
--- a/src/main.js
+++ b/src/main.js
@@ -13,7 +13,6 @@ import {
import pinia from './pinia.js'
import App from './App.vue'
import bundledManifest from './manifest.json'
-import customComponents from './customComponents.js'
import registry from './registry.js'
// Library CSS — must be an explicit import (webpack tree-shakes side-effect imports from aliased packages).
@@ -93,15 +92,12 @@ const router = new VueRouter({
tryLoadTranslations()
-// Pass shallow copies of the registry maps — the lib exports
-// `defaultPageTypes` (and consumers' `customComponents`) as frozen module
-// objects in some bundle shapes, and Vue.extend() mutates component
-// definitions to attach `_Ctor`. Cloning yields extensible objects without
-// changing the values the lib resolves at render time.
+// Pass shallow copies of the registry maps — the lib exports `defaultPageTypes`
+// (and consumers' `registry`) as frozen module objects in some bundle shapes,
+// and Vue.extend() mutates component definitions to attach `_Ctor`. Cloning
+// yields extensible objects without changing the values the lib resolves at
+// render time.
const pageTypesProp = { ...defaultPageTypes }
-const customComponentsProp = { ...customComponents }
-// Shallow-clone the v2 registry for the same reason — Vue.extend() attaches
-// `_Ctor` to component definitions, so the entries need to be extensible.
const registryProp = { ...registry }
// Create the Vue instance — this installs Pinia and sets it active, so the
@@ -114,9 +110,8 @@ new Vue({
render: h => h(App, {
props: {
manifest: bundledManifest,
- customComponents: customComponentsProp,
- pageTypes: pageTypesProp,
registry: registryProp,
+ pageTypes: pageTypesProp,
},
}),
}).$mount('#content')
diff --git a/src/registry.js b/src/registry.js
index 06ee6c0..91fdd9b 100644
--- a/src/registry.js
+++ b/src/registry.js
@@ -1,30 +1,70 @@
-// SPDX-License-Identifier: EUPL-1.2
-//
-// v2 component registry for OpenBuilt — passed as the `registry` prop on
-// CnAppRoot. Each entry declares its `kind` so CnAppRoot can validate and
-// dispatch components correctly (REQ-MVR-002).
-//
-// Recognised kinds (RegistryKindError.js):
-// widget — renderable in page slots (body, sidebar, tab:*, section:*)
-// modal — openable via cnOpenModal(key, props)
-// page — full custom page component (for type:"custom" pages)
-// form-field — field type injected into CnFormPage
-// cell-renderer — column formatter in CnIndexPage tables
-//
-// All `type: "custom"` pages in manifest.json reference their component via
-// `pages[].component`; those components are registered here as kind: "page".
-//
-// Custom tabs on VirtualAppDetail (ApplicationManifestTab, ApplicationVersionsTab,
-// ApplicationDiffTab, ApplicationIconTab) are referenced via
-// config.sidebarTabs[].component — those remain resolved through
-// customComponents (carry-forward prop) until a dedicated "sidebar-tab" kind
-// lands in the lib. They are NOT in this registry.
-//
-// Custom cards and header/actions components are resolved via customComponents
-// too — they are pass-through component references in config.cardComponent,
-// pages[].headerComponent, and pages[].actionsComponent.
-//
-// See ADR-024 (app manifest) and ADR-036 (manifest v2).
+/**
+ * OpenBuilt v2 component registry (ADR-036).
+ *
+ * Kind-tagged map passed as the `registry` prop to CnAppRoot. CnPageRenderer
+ * resolves every manifest-referenced component name (type:"custom" pages,
+ * cardComponent, headerComponent, actionsComponent, sidebarTabs[].component)
+ * against this map. Only entries with `kind === "page"` are used for page and
+ * slot-override dispatch — the `kind` field is the discriminator CnPageRenderer
+ * keys on (see `resolveCustomComponent` in CnPageRenderer.vue). Future entry
+ * kinds (`"modal"`, `"widget"`, `"form-field"`, `"cell-renderer"`) will be
+ * added here as the library ships support for them.
+ *
+ * Replace the deprecated `customComponents` prop: all components previously
+ * passed through `customComponents` are now registered here with
+ * `kind: "page"` so CnPageRenderer resolves them through a single v2 path and
+ * CnAppRoot stops emitting the "customComponents is deprecated" console warning.
+ *
+ * Resolution order at runtime (CnPageRenderer):
+ * 1. Built-in page types (CnIndexPage, CnDetailPage, CnDashboardPage, …)
+ * 2. Built-in widget types (data, metadata, audit-trail, version-info, …)
+ * 3. registry (this file) ← all consumer-injected components (ADR-036)
+ *
+ * See ADR-024 (app manifest) and ADR-036 (manifest v2 kind-tagged registry).
+ *
+ * SPDX-License-Identifier: EUPL-1.2
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
+ */
+
+// ── Virtual apps — index card ─────────────────────────────────────────────────
+
+// VirtualApps index card — name, status pill, version, "live" marker, caller's
+// role; click navigates to VirtualAppDetail.
+import ApplicationCard from './components/ApplicationCard.vue'
+
+// ── Virtual apps — detail sidebar tabs ───────────────────────────────────────
+
+// VirtualAppDetail sidebar tab: raw-JSON manifest editor (the visual designer
+// lives at /builder/:slug/pages).
+import ApplicationManifestTab from './components/tabs/ApplicationManifestTab.vue'
+
+// VirtualAppDetail sidebar tab: version history + rollback.
+import ApplicationVersionsTab from './components/tabs/ApplicationVersionsTab.vue'
+
+// VirtualAppDetail sidebar tab: manifest diff between versions.
+import ApplicationDiffTab from './components/tabs/ApplicationDiffTab.vue'
+
+// VirtualAppDetail sidebar tab: icon upload and preview.
+import ApplicationIconTab from './components/tabs/ApplicationIconTab.vue'
+
+// ── Virtual apps — actions components ────────────────────────────────────────
+
+// VirtualApps index actions bar — "Add application" button that opens the
+// four-step CreateApplicationWizard (openbuilt-app-creation-wizard).
+import VirtualAppsActions from './components/VirtualAppsActions.vue'
+
+// VirtualAppDetail actions bar — Publish (OR lifecycle transition), Manage
+// permissions (PermissionsModal, ADR-004 modal isolation), Design pages, Open
+// virtual app.
+import ApplicationDetailActions from './components/ApplicationDetailActions.vue'
+
+// ── Virtual apps — detail header ──────────────────────────────────────────────
+
+// VirtualAppDetail headerComponent (openbuilt-app-detail-overview
+// REQ-OBADO-001 / REQ-OBADO-011) — purpose-built maintainer dashboard
+// replacing the generic main-area data widget. Owns hero strip + version pill
+// tabs + window toggle + KPI grid + activity chart + structural widgets.
+import ApplicationDetailHeader from './components/applicationDetail/ApplicationDetailHeader.vue'
// ── Custom page components (kind: "page") ────────────────────────────────────
@@ -32,48 +72,49 @@
// placement. Handles both /schemas (shortcut) and /builder/:slug/schemas[/:id].
import SchemaDesignerView from './views/SchemaDesigner.vue'
-// Template gallery — browse seeded ApplicationTemplate records and clone
-// one into a new virtual app (openbuilt-templates-marketplace).
-
-// Visual manifest page designer — three-pane editor that reads and writes
-// a virtual app's manifest via PATCH (REQ-OBPD-003).
+// Visual manifest page designer — three-pane editor that reads and writes a
+// virtual app's manifest via PATCH (REQ-OBPD-003).
import PageDesignerView from './views/PageDesignerHost.vue'
-// Export-jobs status list — Phase-2 "export to real Nextcloud app" runs.
-
// Virtual-app host — nested CnAppRoot rendering a virtual app's own manifest.
import BuilderHostView from './views/BuilderHost.vue'
-// Features & Roadmap page — wrapper around CnFeaturesAndRoadmapView.
+// ── Helper ───────────────────────────────────────────────────────────────────
+
+/**
+ * Wrap a Vue component into the v2 registry shape required by CnAppRoot's
+ * `registry` prop (`kind: "page"` is the discriminator CnPageRenderer keys
+ * page and slot-override dispatch off).
+ *
+ * @param {object} component Vue component options.
+ *
+ * @return {object} A `{ kind: "page", component }` registry entry.
+ */
+function page(component) {
+ return { kind: 'page', component }
+}
-// ── Widget components (kind: "widget") ───────────────────────────────────────
+// ── Registry export ──────────────────────────────────────────────────────────
-// (No consumer-registered widget kinds in the initial v2 migration.
-// The dashboard stats-block widgets use the lib's built-in "stats-block"
-// widget key and do not need a registry entry here.)
+export default {
+ // VirtualApps index card component.
+ ApplicationCard: page(ApplicationCard),
-// ── Modal components (kind: "modal") ─────────────────────────────────────────
+ // VirtualAppDetail sidebar tabs.
+ ApplicationManifestTab: page(ApplicationManifestTab),
+ ApplicationVersionsTab: page(ApplicationVersionsTab),
+ ApplicationDiffTab: page(ApplicationDiffTab),
+ ApplicationIconTab: page(ApplicationIconTab),
-// (No modal entries for the initial v2 migration.
-// The CreateApplicationWizard and PermissionsModal are opened imperatively
-// by VirtualAppsActions / ApplicationDetailActions components rather than
-// via cnOpenModal(); they will be registered here when those components
-// are refactored to use the modal registry pattern.)
+ // Actions bar components.
+ VirtualAppsActions: page(VirtualAppsActions),
+ ApplicationDetailActions: page(ApplicationDetailActions),
-// ── Registry export ──────────────────────────────────────────────────────────
+ // Header component for the maintainer dashboard (detail page override).
+ ApplicationDetailHeader: page(ApplicationDetailHeader),
-export default {
// Custom page components — resolved by CnPageRenderer for type:"custom" pages.
- SchemaDesignerView: {
- kind: 'page',
- component: SchemaDesignerView,
- },
- PageDesignerView: {
- kind: 'page',
- component: PageDesignerView,
- },
- BuilderHostView: {
- kind: 'page',
- component: BuilderHostView,
- },
+ SchemaDesignerView: page(SchemaDesignerView),
+ PageDesignerView: page(PageDesignerView),
+ BuilderHostView: page(BuilderHostView),
}