diff --git a/package-lock.json b/package-lock.json index bda8fc68..1fee71ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@babel/core": "^7.22.9", "@codemirror/lang-json": "^6.0.0", - "@conduction/nextcloud-vue": "^2.19.0", + "@conduction/nextcloud-vue": "^2.21.0", "@nextcloud/auth": "^2.6.0", "@nextcloud/axios": "^2.5.0", "@nextcloud/capabilities": "^1.2.1", @@ -2192,9 +2192,9 @@ } }, "node_modules/@conduction/nextcloud-vue": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.19.0.tgz", - "integrity": "sha512-gSLl4RZ7hy1e2TBuzYZLiTLBMggRYgfuxFMva59JBhb1EP93GgvEd/HpQcg+zoBL9FJPgJw9ir2OGf9Tore7og==", + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.21.0.tgz", + "integrity": "sha512-5HjI4X8k2IYxUeBdHa2OK/MnLhOFf4HxkF5dUGl42dWmYPDaPHjvawDMZcUcyP6wsP+rk0QzmPov4FGu/4Rn7Q==", "license": "EUPL-1.2", "dependencies": { "@ckpack/vue-color": "^1.6.0", @@ -2256,7 +2256,7 @@ "dompurify": "^3.0.0", "eslint": "^8.56.0 || ^9.0.0 || ^10.0.0", "eslint-plugin-vue": "^9.21.0 || ^10.0.0", - "gridstack": "^12.0.0", + "gridstack": "^12.0.0 || ^13.0.0", "marked": "^12.0.0", "pinia": "^2.0.0 || ^3.0.0", "vue": "^3.5.0", diff --git a/package.json b/package.json index 549cf332..716fa859 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "dependencies": { "@babel/core": "^7.22.9", "@codemirror/lang-json": "^6.0.0", - "@conduction/nextcloud-vue": "^2.19.0", + "@conduction/nextcloud-vue": "^2.21.0", "@nextcloud/auth": "^2.6.0", "@nextcloud/axios": "^2.5.0", "@nextcloud/capabilities": "^1.2.1", diff --git a/src/manifest.json b/src/manifest.json index c72c5a55..24ea316e 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -831,15 +831,15 @@ { "id": "Flows", "route": "/flows", - "type": "flows", + "type": "index", "title": "Flows", - "config": { "app": "stackiq" }, - "_note": "ADR-110 Decision 4: a flow is app-specific, so the authoring surface lives here rather than behind a deep link to another app's list. Rendered by the shared CnFlowsPage page type over OpenRegister's one native flow store (ADR-065), scoped to this app." + "config": { "entitySource": "flows", "app": "stackiq" }, + "_note": "ADR-110 Decision 4: a flow is app-specific, so the authoring surface lives here rather than behind a deep link to another app's list. An ordinary index over the named `flows` source (config.entitySource) rather than the deprecated `flows` page type, reading OpenRegister's one native flow store (ADR-065), scoped to this app by config.app." }, { "id": "FlowDetail", "route": "/flows/:id", - "type": "flow-detail", + "type": "flow", "title": "Flow", "config": { "app": "stackiq" }, "_note": "The shared CnFlowDetail canvas over the same single engine. Controls render in the NC app sidebar so the canvas keeps full width." diff --git a/tests/e2e/workflows/crud-persistence.spec.ts b/tests/e2e/workflows/crud-persistence.spec.ts index 7587c34e..4b388d90 100644 --- a/tests/e2e/workflows/crud-persistence.spec.ts +++ b/tests/e2e/workflows/crud-persistence.spec.ts @@ -63,6 +63,40 @@ import { type VoorzieningenConfig, } from './_fixtures' +/** + * Wait for the edit dialog after an `Edit` row action, wherever it opens. + * + * Since nextcloud-vue 2.21 (#806) a record whose schema has a same-schema + * DETAIL page is edited on that page, not in a modal launched from the table: + * the modal renders only the schema's flat scalars and cannot express a record + * whose related rows live elsewhere. `CnPageRenderer` sets `editOpensDetail` + * from `detailPageByRegisterSchema`. + * + * Which route applies is a property of the SCHEMA, so this branches instead of + * assuming. Either way it returns a real, visible edit dialog — the assertion + * is not weakened, only its route. + * + * @param page The Playwright page. + * @return The visible edit dialog locator. + */ +async function editDialogAfterEdit(page: import('@playwright/test').Page) { + const dialog = page.locator('[role="dialog"], .modal-container').first() + const direct = await dialog + .waitFor({ state: 'visible', timeout: 5000 }) + .then(() => true) + .catch(() => false) + if (!direct) { + const headerEdit = page.getByRole('button', { name: /^Edit$/ }).first() + await expect( + headerEdit, + 'detail page header Edit button visible', + ).toBeVisible({ timeout: 15000 }) + await headerEdit.click() + await dialog.waitFor({ state: 'visible', timeout: 15000 }) + } + return dialog +} + let apiCtx: APIRequestContext let cfg: VoorzieningenConfig @@ -204,8 +238,7 @@ test.describe('Contactpersoon CRUD-persistence', () => { await openRowActions(page, contactsUid) await clickAction(page, 'Edit') - const editDialog = page.locator('[role="dialog"], .modal-container').first() - await editDialog.waitFor({ state: 'visible', timeout: 15000 }) + const editDialog = await editDialogAfterEdit(page) // The editor is populated from the persisted row — the values we created // read back into the form (detail read-back persistence). @@ -231,8 +264,7 @@ test.describe('Contactpersoon CRUD-persistence', () => { await openRowActions(page, contactsUid) await clickAction(page, 'Edit') - const editDialog = page.locator('[role="dialog"], .modal-container').first() - await editDialog.waitFor({ state: 'visible', timeout: 15000 }) + const editDialog = await editDialogAfterEdit(page) // The edit form is pre-filled with the existing UID — proves the row // loaded into the editor (read-back persistence). await expect(