Skip to content

Commit 74fda38

Browse files
rubenvdlindeConduction Release Bot
andauthored
feat(nav): the flow list is an ordinary index, and the editor is flow (#1402)
* feat(nav): the flow list is an ordinary index, and the editor is `flow` No custom page, and no page type of its own for the list half. "type": "index", "config": { "entitySource": "flows", "app": "dossiq" } "type": "flow", "config": { "app": "dossiq" } WHY THIS IS NOW POSSIBLE. A flow definition is deliberately not an OpenRegister object, so `type: "index"` had nothing to bind to and every flow list needed either a bespoke `type: "custom"` page or a page type of its own. Named index sources (@conduction/nextcloud-vue 2.20.0) remove that: the manifest names a registered non-object collection and the index loads it. `flows` and `flow-detail` remain registered as deprecated aliases, so this is a migration rather than a flag day. The bump to ^2.20.0 is required, not incidental: below it the runtime does not register `flow` at all, and a manifest naming a page type the runtime does not know renders nothing rather than failing. That failure mode is why the types were checked against the shipped schema rather than by eye - `type` against the page-type enum and `entitySource` against its allowed values, both read out of the 2.20.0 tarball. Control build against the regenerated lock: webpack compiles, 24 artifacts. A resolved lock is not a working tree. * fix(manifest-check): the INSTALLED schema wins over the vendored copy check:manifest rejected `type: "flow"` on a manifest that is correct. The reason is the resolution order, not the manifest: [validate-manifest] schema: tests/schemas/app-manifest-v2.schema.json [validate-manifest] schema.version: 2.25.0 - /pages/51/type must be equal to one of the allowed values The vendored copy was checked BEFORE node_modules, so it shadowed the schema the shipped runtime actually enforces. It sat at 2.25.0 and predates `flow`; the installed @conduction/nextcloud-vue 2.20.0 carries schema 2.26.0, which accepts it and whose runtime registers the page type. The check was reading last month's grammar and calling today's manifest wrong. That ordering is a drift machine rather than a one-off: a vendored copy never fails, it just quietly keeps validating against a snapshot while the rules move. The same shape cost this fleet a round of blocked PRs earlier today, when a stale hydra-gates copy of this very schema rejected thirteen app manifests. So node_modules now wins. A manifest has to satisfy the schema its own dependency ships - that is the version whose runtime will read it. The vendored copy stays as a fallback for a tree with no node_modules (fresh checkout, a CI leg that skips install) and is refreshed to 2.26.0 so the fallback is not itself stale, but it no longer overrules what is installed. Verified both paths: default resolution picks node_modules and passes, and forcing the vendored copy via APP_MANIFEST_SCHEMA also passes. * chore(deps): bump @conduction/nextcloud-vue to ^2.21.0 The flow pages need 2.21.0: earlier releases DECLARE a named index source's columns, create button and row actions without reading them, so the migrated page renders a columnless table with no working create action. The lock is the part that matters. CI installs with `npm ci`, which honours package-lock.json and ignores how permissive the caret is — bumping the range alone would change nothing about what actually installs. * fix(manifest): drop 15 inert action entries that render as blank rows `config.actions` is for CUSTOM actions. These 15 entries across seven pages tried to name BUILT-IN ones, in two spellings: "create" (10x, bare string) { "key": "edit", "type": "handler" } (5x, object with no label) Neither works, and neither is inert in the harmless sense. nextcloud-vue's CnIndexPage documents this app by name: `config.actions: ["create", "edit", "delete", {...}]` put three blank rows above the real ones on four different index pages — a full-height, clickable, empty row in the overflow menu. Nothing is lost by removing them. showViewAction / showEditAction / showCopyAction / showDeleteAction all default to true, so the built-ins already render from defaultActions; naming them here only ever added the blanks. These were invisible to the manifest check until now because it preferred a VENDORED schema copy stuck at 2.25.0 over the installed one. Reading the installed 2.26.0 schema is what surfaced them — the schema has rejected this shape since it was written. Verified: the text edit was compared against the same change applied structurally and the two agree exactly; the result validates against 2.26.0 with jsonschema; the diff is 30 deletions and no insertions. * fix(manifest): the configuration wizard opens with welcome, then demo-data ADR-111 rule 4, as corrected in ConductionNL/.github#614: step 1 is the welcome/orientation step and step 2 is the demo-data offer. The first version of that gate demanded demo-data at step 0, which inverted the wizard — this is the CONFIGURATION wizard, where an orientation step earns its place, and the demo-data offer is the second thing an administrator wants, not the first. Only the order changes; no step is added, removed or edited. The text blocks were moved and the result compared against the same reorder applied structurally, so the two had to agree exactly. --------- Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
1 parent c96c5d0 commit 74fda38

5 files changed

Lines changed: 42 additions & 18 deletions

File tree

‎package-lock.json‎

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

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"extends @nextcloud/browserslist-config"
4141
],
4242
"dependencies": {
43-
"@conduction/nextcloud-vue": "^2.20.0",
43+
"@conduction/nextcloud-vue": "^2.21.0",
4444
"@nextcloud/auth": "^2.6.0",
4545
"@nextcloud/axios": "~2.5.2",
4646
"@nextcloud/capabilities": "^1.2.1",

‎src/manifest.json‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
"version": 1,
1010
"completionConfigKey": "setup_completed_version",
1111
"steps": [
12+
{
13+
"id": "welcome",
14+
"type": "info",
15+
"title": "Welkom bij Dossiq",
16+
"body": "Laten we Dossiq klaarzetten. Initialiseer eerst het register; laad daarna optioneel de Bezwaar & Beroep voorbeelddata."
17+
},
1218
{
1319
"id": "demo-data",
1420
"type": "run-action",
@@ -17,12 +23,6 @@
1723
"required": false,
1824
"body": "Load example dossiers, case types and documents so lists, the case timeline and the detail pages show a working product right away. Optional, and safe to run more than once. Skip this on a production install."
1925
},
20-
{
21-
"id": "welcome",
22-
"type": "info",
23-
"title": "Welkom bij Dossiq",
24-
"body": "Laten we Dossiq klaarzetten. Initialiseer eerst het register; laad daarna optioneel de Bezwaar & Beroep voorbeelddata."
25-
},
2626
{
2727
"id": "register-check",
2828
"type": "run-action",
@@ -4558,15 +4558,16 @@
45584558
{
45594559
"id": "Flows",
45604560
"route": "/flows",
4561-
"type": "flows",
4561+
"type": "index",
45624562
"title": "Flows",
4563-
"config": { "app": "dossiq" },
4563+
"config": {
4564+
"entitySource": "flows", "app": "dossiq" },
45644565
"_note": "ADR-110 Decision 4: a flow is app-specific — a dossiq flow operates on cases — so the authoring surface lives here rather than behind a deep link to OpenRegister's list. Custom page rather than type:index because a flow lives in the shared native flow store, not a register/schema, so the object-backed index cannot address it. The body is CnFlowIndexPage semantics scoped app=\"dossiq\" — the same store OpenRegister, integriq and hermiq use, so list/status semantics stay identical fleet-wide. Mirrors openconnector/src/manifest.json:Flows."
45654566
},
45664567
{
45674568
"id": "FlowDetail",
45684569
"route": "/flows/:id",
4569-
"type": "flow-detail",
4570+
"type": "flow",
45704571
"title": "Flow",
45714572
"config": { "app": "dossiq" },
45724573
"sidebarComponent": "FlowDetailSidebar",

‎tests/schemas/app-manifest-v2.schema.json‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"$id": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest-v2.schema.json",
44
"title": "Conduction App Manifest v2",
55
"description": "v2 schema for the JSON-driven page and navigation manifest consumed by @conduction/nextcloud-vue. Introduces a uniform widgets[] array on every page type with a per-slot grid coordinate system, a typed actions[] discriminator, and the required $schema field for version detection. v1 manifests continue to validate against app-manifest.schema.json (unchanged).",
6-
"version": "2.25.0",
6+
"version": "2.26.0",
77
"type": "object",
88
"required": ["$schema", "version"],
99
"allOf": [
@@ -2097,8 +2097,8 @@
20972097
},
20982098
"type": {
20992099
"type": "string",
2100-
"enum": ["index", "detail", "dashboard", "logs", "settings", "chat", "files", "form", "map", "roadmap", "search", "wiki", "flows", "flow-detail", "custom"],
2101-
"description": "Page type. Closed enum of 16 supported types. 'roadmap' mounts CnFeaturesAndRoadmapPage (features + GitHub-issue-backed roadmap). 'search' mounts CnSearchPage (cross-schema query + facet sidebar + results list; consumers wire the actual search via @search). 'wiki' mounts CnWikiPage (manifest-declared markdown article + optional sidebar tree; MUST declare config.register + config.schema). 'flows' mounts CnFlowsPage (the app-scoped flow list) and 'flow-detail' mounts CnFlowEditorPage (the shared node/edge canvas); both take config.app to scope to the owning app, and neither can be expressed as 'index'/'detail' because a flow lives in OpenRegister's native flow store rather than a register/schema pair (ADR-110 Decision 4). 'custom' requires a _note field explaining why a standard type was not feasible."
2100+
"enum": ["index", "detail", "dashboard", "logs", "settings", "chat", "files", "form", "map", "roadmap", "search", "wiki", "flow", "flows", "flow-detail", "custom"],
2101+
"description": "Page type. Closed enum of 17 supported types. 'flow' opens ONE flow in the editor; the flow LIST is an ordinary 'index' with config.source='flows'. 'flows' and 'flow-detail' are DEPRECATED aliases kept for migration — 'flows' predates named index sources and 'flow-detail' is the old name for 'flow'. 'roadmap' mounts CnFeaturesAndRoadmapPage (features + GitHub-issue-backed roadmap). 'search' mounts CnSearchPage (cross-schema query + facet sidebar + results list; consumers wire the actual search via @search). 'wiki' mounts CnWikiPage (manifest-declared markdown article + optional sidebar tree; MUST declare config.register + config.schema). 'flows' mounts CnFlowsPage (the app-scoped flow list) and 'flow-detail' mounts CnFlowEditorPage (the shared node/edge canvas); both take config.app to scope to the owning app, and neither can be expressed as 'index'/'detail' because a flow lives in OpenRegister's native flow store rather than a register/schema pair (ADR-110 Decision 4). 'custom' requires a _note field explaining why a standard type was not feasible."
21022102
},
21032103
"title": {
21042104
"type": "string",
@@ -2150,6 +2150,15 @@
21502150
"additionalProperties": true,
21512151
"allOf": [{ "$ref": "#/$defs/sentinelGuardedValue" }],
21522152
"properties": {
2153+
"entitySource": {
2154+
"type": "string",
2155+
"enum": ["flows"],
2156+
"description": "Name a registered NON-OBJECT entity collection for a type='index' page, instead of register+schema. Deliberately NOT called `source`: that key is already taken on page config and is polymorphic (a URL string in some manifests, an object with `params` in others), so reusing it would give one key two meanings and break six deployed shillinq pages. A flow definition is deliberately not an OpenRegister object, so an index had nothing to bind to and such lists became bespoke type='custom' pages. With a source the index loads the list itself. Takes precedence over register/schema; non-empty `objects` still wins over both. Registered sources live in src/composables/indexSources.js."
2157+
},
2158+
"app": {
2159+
"type": "string",
2160+
"description": "Scopes a named `source` to one app (e.g. source='flows' with app='dossiq' lists that app's flows)."
2161+
},
21532162
"register": {
21542163
"type": "string",
21552164
"description": "OpenRegister register slug."

‎tests/validate-manifest.js‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,22 @@ const REPO_ROOT = path.resolve(__dirname, '..')
3333

3434
const MANIFEST_PATH = path.join(REPO_ROOT, 'src', 'manifest.json')
3535

36+
// THE INSTALLED SCHEMA WINS OVER THE VENDORED COPY.
37+
//
38+
// It used to be the other way round, and that ordering is a drift machine: the
39+
// vendored copy shadows the one the shipped runtime actually enforces, so the
40+
// check keeps passing against a snapshot of the rules while the rules move.
41+
// Measured here — the vendored copy sat at 2.25.0 and rejected `type: "flow"`,
42+
// which the installed 2.20.0 package (schema 2.26.0) accepts and the runtime
43+
// registers. The manifest was right and the check was reading last month's
44+
// grammar.
45+
//
46+
// A manifest has to satisfy the schema its own dependency ships. The vendored
47+
// copy stays as a fallback for a tree with no node_modules — a fresh checkout,
48+
// a CI leg that skips install — but it no longer gets to overrule what is
49+
// installed.
3650
const SCHEMA_CANDIDATES = [
3751
process.env.APP_MANIFEST_SCHEMA,
38-
path.join(REPO_ROOT, 'tests', 'schemas', 'app-manifest-v2.schema.json'),
3952
path.join(
4053
REPO_ROOT,
4154
'node_modules',
@@ -45,6 +58,7 @@ const SCHEMA_CANDIDATES = [
4558
'schemas',
4659
'app-manifest-v2.schema.json',
4760
),
61+
path.join(REPO_ROOT, 'tests', 'schemas', 'app-manifest-v2.schema.json'),
4862
path.join(
4963
REPO_ROOT,
5064
'..',

0 commit comments

Comments
 (0)