diff --git a/CHANGELOG.md b/CHANGELOG.md index ea6ae67..23e0bfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), #### Profile-level +- **Liquibase**: Development changelog 78 sets a description, a metadata URL, and a dataset URL on folder Adreces (tree node 12339) in Visor IDEBarcelona. Gestió municipal (node 12338) stays empty ([sitmun-viewer-app#173](https://github.com/sitmun/sitmun-viewer-app/issues/173)). +- **Liquibase**: Development changelog 79 moves IDE Menorca folder download zips from `TNO_METAURL` to `TNO_DATAURL` and clears the metadata URL. Those zip names have no GeoNetwork record, so the catalog window shows the file under download data. - **Liquibase**: PostgreSQL and Oracle changelog 27, and development changelog 74, add `PGI_OPTIONS` and format code `AUTO` ([#77](https://github.com/sitmun/sitmun-application-stack/issues/77)). - **Liquibase**: Development changelog 75 seeds GetFeatureInfo fields on IDE genèric Menorca cartography 1304, Trams del camí de cavalls (`tu007rts_ccavalls`): route, kind, max easting, and website. Spanish and Catalan labels are translations; English is the stored default ([#77](https://github.com/sitmun/sitmun-application-stack/issues/77)). - **Liquibase**: Development changelog 76 seeds seven GetFeatureInfo fields on cartography 4658, RPT Sòl Rústic (`OR007RPT_solrustic`): soil class, category, qualification, settlement names, area, and perimeter. Area and perimeter use two fraction digits. diff --git a/e2e/viewer/folder-catalog-info.spec.ts b/e2e/viewer/folder-catalog-info.spec.ts new file mode 100644 index 0000000..d2fa515 --- /dev/null +++ b/e2e/viewer/folder-catalog-info.spec.ts @@ -0,0 +1,110 @@ +import { expect, test, type Page } from '@playwright/test'; +import { + APP_ID, + isBackendRequest, + NON_RADIO_ROOT_FOLDER_TITLE, + RADIO_FOLDER_TITLE, + readViewerCredentials, + TERRITORY_ID, +} from './fixtures'; + +const FOLDER_DB_ID = 1; +const FOLDER_DESCRIPTION = 'Carrers, números de portal i illes urbanes del municipi.'; +const METADATA_URL = 'https://ide.example.cat/geonetwork/srv/cat/catalog.search#/metadata/adreces'; +const DATASET_URL = 'https://ide.example.cat/descarrega/adreces.zip'; + +async function patchFolderInfo(page: Page): Promise { + const login = await page.request.post('/backend/api/authenticate/admin', { + data: { username: 'admin', password: 'admin' }, + }); + expect(login.ok(), `admin login failed: ${login.status()}`).toBeTruthy(); + const response = await page.request.patch(`/backend/api/tree-nodes/${FOLDER_DB_ID}`, { + headers: { + 'X-SITMUN-Client': 'admin', + 'Content-Type': 'application/merge-patch+json', + }, + data: { + description: FOLDER_DESCRIPTION, + metadataURL: METADATA_URL, + datasetURL: DATASET_URL, + }, + }); + const body = (await response.json()) as Record; + expect(response.ok(), `patch tree-node ${FOLDER_DB_ID} failed: ${response.status()} ${JSON.stringify(body)}`).toBeTruthy(); + expect(body['description'], JSON.stringify(body)).toBe(FOLDER_DESCRIPTION); + expect(body['metadataURL']).toBe(METADATA_URL); + expect(body['datasetURL']).toBe(DATASET_URL); +} + +async function openCatalog(page: Page): Promise { + const credentials = await readViewerCredentials(); + await page.goto('/auth/login'); + await page.locator('input[name="username"]').fill(credentials.username); + await page.locator('input[name="password"]').fill(credentials.password); + await page.locator('form .login-button button').click(); + await expect(page).toHaveURL(/\/user\/dashboard/); + + const profile = page.waitForResponse( + (response) => + isBackendRequest(response, `/config/client/profile/${APP_ID}/${TERRITORY_ID}`, 'GET') && + response.ok(), + ); + await page.goto(`/user/map/${APP_ID}/${TERRITORY_ID}`, { waitUntil: 'domcontentloaded' }); + const profileResponse = await profile; + const profileBody = (await profileResponse.json()) as { + trees?: Array<{ nodes?: Record> }>; + }; + const node = profileBody.trees + ?.flatMap((tree) => Object.entries(tree.nodes ?? {})) + .find(([id]) => id === 'node/1')?.[1]; + expect(node?.['description'], JSON.stringify(node)).toBe(FOLDER_DESCRIPTION); + expect(node?.['metadataURL']).toBe(METADATA_URL); + expect(node?.['datasetURL']).toBe(DATASET_URL); + await page.locator('#tc-slot-toc').waitFor({ state: 'attached', timeout: 90_000 }); + await page.locator('.tc-tools-panel').evaluate((panel) => { + panel.classList.remove('tc-collapsed-right'); + }); + await expect(page.locator('.tc-tools-panel')).not.toHaveClass(/tc-collapsed-right/); + await expect(page.locator('#tc-slot-toc .tc-ctl-lcat-tree')).toBeVisible({ timeout: 30_000 }); +} + +function folderRow(page: Page, title: string) { + return page.locator('#tc-slot-toc li.tc-ctl-lcat-node').filter({ + has: page.locator(':scope > span, :scope > .tc-ctl-lcat-node-title').filter({ + hasText: new RegExp(`^${title}$`), + }), + }); +} + +test('folder information window follows the folder kind', async ({ page }) => { + await patchFolderInfo(page); + await openCatalog(page); + + const filled = folderRow(page, NON_RADIO_ROOT_FOLDER_TITLE); + const empty = folderRow(page, RADIO_FOLDER_TITLE); + await expect(filled).toBeVisible(); + await filled.getByRole('button', { name: /Expandir|Expand|Desplegar/i }).click(); + await expect(empty).toBeVisible(); + + await expect(filled.locator(':scope > .tc-ctl-lcat-btn-info')).toBeVisible(); + await expect(empty.locator(':scope > .tc-ctl-lcat-btn-info')).toHaveCount(0); + + await page.screenshot({ + path: '/tmp/sitmun-issue-173-implemented/01-catalog.png', + }); + + await filled.locator(':scope > .tc-ctl-lcat-btn-info').click(); + const dialog = page.locator('#tc-slot-toc .tc-ctl-lcat-info'); + await expect(dialog).toBeVisible(); + await expect(dialog).toContainText(FOLDER_DESCRIPTION); + await expect(dialog.locator('a.tc-file-link').nth(0)).toHaveAttribute('href', METADATA_URL); + await expect(dialog.locator('a.tc-file-link').nth(1)).toHaveAttribute('href', DATASET_URL); + await expect(dialog).toContainText( + /Descripció del grup de capes|Descripción del grupo de capas|Layer group description/, + ); + await expect(dialog).not.toContainText(/ID de la capa|Layer ID|Identificador de capa/); + + await page.screenshot({ + path: '/tmp/sitmun-issue-173-implemented/02-folder-window.png', + }); +}); diff --git a/front/admin/sitmun-admin-app b/front/admin/sitmun-admin-app index 3dc231e..7cffd20 160000 --- a/front/admin/sitmun-admin-app +++ b/front/admin/sitmun-admin-app @@ -1 +1 @@ -Subproject commit 3dc231e6df013f78e585858a29fe53d2329981a2 +Subproject commit 7cffd2090653b7a5586de66cf7befe192dec2ac5 diff --git a/front/viewer/sitmun-viewer-app b/front/viewer/sitmun-viewer-app index a52f04e..b709522 160000 --- a/front/viewer/sitmun-viewer-app +++ b/front/viewer/sitmun-viewer-app @@ -1 +1 @@ -Subproject commit a52f04e1ca051c228fe2df7abdd9afd6fbb9b973 +Subproject commit b709522a82d3eec061f53e90ea233ce97c0d530f diff --git a/playwright.viewer.config.ts b/playwright.viewer.config.ts index 6c481fd..98dd751 100644 --- a/playwright.viewer.config.ts +++ b/playwright.viewer.config.ts @@ -71,7 +71,7 @@ export default defineConfig({ }, { name: 'viewer-catalog', - testMatch: /layer-catalog\.spec\.ts/, + testMatch: /(?:layer-catalog|folder-catalog-info)\.spec\.ts/, dependencies: ['viewer-setup'], use: { ...devices['Desktop Chrome'] }, }, diff --git a/profiles/development/backend/liquibase/changelog/78_dev_folder_metadata_adreces.yaml b/profiles/development/backend/liquibase/changelog/78_dev_folder_metadata_adreces.yaml new file mode 100644 index 0000000..a1fc3a6 --- /dev/null +++ b/profiles/development/backend/liquibase/changelog/78_dev_folder_metadata_adreces.yaml @@ -0,0 +1,30 @@ +databaseChangeLog: + - changeSet: + id: 78-dev-folder-metadata-adreces + author: sitmun + context: dev + dbms: h2,postgresql,oracle + comment: > + Visor IDEBarcelona (application 15, tree 37). Folder Adreces (node 12339) + gets a description, a metadata URL, and a dataset URL so the viewer + catalog can open the folder information window. Gestió municipal + (node 12338) stays empty and has no button. + preConditions: + - onFail: MARK_RAN + sqlCheck: + expectedResult: 1 + sql: > + SELECT CASE + WHEN (SELECT COUNT(*) FROM STM_TREE_NOD + WHERE TNO_ID = 12339 + AND TNO_NAME = 'Adreces' + AND TNO_METAURL IS NULL) = 1 + THEN 1 ELSE 0 END + changes: + - sql: + sql: | + UPDATE STM_TREE_NOD + SET TNO_ABSTRACT = 'Carrers, números de portal i illes urbanes del municipi.', + TNO_METAURL = 'https://www.icgc.cat/ca/Geoinformacio-i-mapes/Geoinformacio/Geoinformacio-de-referencia', + TNO_DATAURL = 'https://www.icgc.cat/ca/Descarregues' + WHERE TNO_ID = 12339; diff --git a/profiles/development/backend/liquibase/changelog/79_dev_folder_download_urls.yaml b/profiles/development/backend/liquibase/changelog/79_dev_folder_download_urls.yaml new file mode 100644 index 0000000..22b18eb --- /dev/null +++ b/profiles/development/backend/liquibase/changelog/79_dev_folder_download_urls.yaml @@ -0,0 +1,29 @@ +databaseChangeLog: + - changeSet: + id: 79-dev-folder-download-urls + author: sitmun + context: dev + dbms: h2,postgresql,oracle + comment: > + IDE Menorca folder nodes store a descarregues zip in TNO_METAURL and + leave TNO_DATAURL empty, so the catalog window shows a ZIP under + metadata. Those zip names have no GeoNetwork record. Move the zip to + the dataset URL and clear the metadata URL. + preConditions: + - onFail: MARK_RAN + sqlCheck: + expectedResult: 1 + sql: > + SELECT CASE + WHEN (SELECT COUNT(*) FROM STM_TREE_NOD + WHERE TNO_DATAURL IS NULL + AND TNO_METAURL LIKE 'https://ide.cime.es/descarregues/%.zip') > 0 + THEN 1 ELSE 0 END + changes: + - sql: + sql: | + UPDATE STM_TREE_NOD + SET TNO_DATAURL = TNO_METAURL, + TNO_METAURL = NULL + WHERE TNO_DATAURL IS NULL + AND TNO_METAURL LIKE 'https://ide.cime.es/descarregues/%.zip'; diff --git a/profiles/development/backend/liquibase/master.xml b/profiles/development/backend/liquibase/master.xml index a74edaf..9de25a7 100644 --- a/profiles/development/backend/liquibase/master.xml +++ b/profiles/development/backend/liquibase/master.xml @@ -84,4 +84,6 @@ + +