From 980dbc217ade72f7f002f70f400238245610f2e2 Mon Sep 17 00:00:00 2001 From: Francisco J Lopez-Pellicer Date: Tue, 20 Oct 2026 08:37:08 +0200 Subject: [PATCH 1/6] chore(stack): point submodules at Boot 4.1.1 and Angular 22.2.3 Pin shared, backend, proxy, mbtiles, admin, and viewer gitlinks to the LTR merged tips. Move root CI and front image to Node 24.22.0 (Android E2E stays on 22). Keep release line 1.2.9. --- .github/workflows/e2e.yml | 24 ++++++++++++------------ CHANGELOG.md | 1 + README.md | 4 ++-- back/backend/sitmun-backend-core | 2 +- back/mbtiles/sitmun-mbtiles | 2 +- back/proxy/sitmun-proxy-middleware | 2 +- back/shared/sitmun-shared | 2 +- e2e/README.md | 2 +- front/Dockerfile | 4 ++-- front/admin/sitmun-admin-app | 2 +- front/viewer/sitmun-viewer-app | 2 +- 11 files changed, 24 insertions(+), 23 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index f722f9e..0eab7af 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -26,10 +26,10 @@ jobs: chmod +x back/shared/sitmun-shared/gradlew back/shared/sitmun-shared/gradlew -p back/shared/sitmun-shared publishToMavenLocal - - name: Set up Node 20 + - name: Set up Node 24.22.0 uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '24.22.0' cache: npm cache-dependency-path: | package-lock.json @@ -81,10 +81,10 @@ jobs: chmod +x back/shared/sitmun-shared/gradlew back/shared/sitmun-shared/gradlew -p back/shared/sitmun-shared publishToMavenLocal - - name: Set up Node 20 + - name: Set up Node 24.22.0 uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '24.22.0' cache: npm cache-dependency-path: | package-lock.json @@ -136,10 +136,10 @@ jobs: chmod +x back/shared/sitmun-shared/gradlew back/shared/sitmun-shared/gradlew -p back/shared/sitmun-shared publishToMavenLocal - - name: Set up Node 20 + - name: Set up Node 24.22.0 uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '24.22.0' cache: npm cache-dependency-path: | package-lock.json @@ -196,10 +196,10 @@ jobs: chmod +x back/shared/sitmun-shared/gradlew back/shared/sitmun-shared/gradlew -p back/shared/sitmun-shared publishToMavenLocal - - name: Set up Node 20 + - name: Set up Node 24.22.0 uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '24.22.0' cache: npm cache-dependency-path: | package-lock.json @@ -256,10 +256,10 @@ jobs: chmod +x back/shared/sitmun-shared/gradlew back/shared/sitmun-shared/gradlew -p back/shared/sitmun-shared publishToMavenLocal - - name: Set up Node 20 + - name: Set up Node 24.22.0 uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '24.22.0' cache: npm cache-dependency-path: package-lock.json @@ -305,10 +305,10 @@ jobs: chmod +x back/shared/sitmun-shared/gradlew back/shared/sitmun-shared/gradlew -p back/shared/sitmun-shared publishToMavenLocal - - name: Set up Node 20 + - name: Set up Node 22 uses: actions/setup-node@v5 with: - node-version: '20' + node-version: '22' cache: npm cache-dependency-path: | package-lock.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 62d2b8b..85fc7f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), #### Stack-level +- **Toolchain**: Submodule gitlinks point at Spring Boot `4.1.1` (shared, backend, proxy, mbtiles), Angular `22.2.3` / Node `24.22.0` (admin, viewer), and Gradle `8.14.6`. Root image and CI use Node `24.22.0`; mobile Android E2E stays on Node `22`. Published shared coordinate remains `1.2.9`. - **Viewer**: The stack points at viewer `dev`, which replaces filler control-spec expects, deletes the unused control loader, drops three local `any` casts, and removes comments that name the wrong type or narrate the next line ([sitmun-viewer-app#199](https://github.com/sitmun/sitmun-viewer-app/pull/199), [#200](https://github.com/sitmun/sitmun-viewer-app/pull/200), [#201](https://github.com/sitmun/sitmun-viewer-app/pull/201), [#202](https://github.com/sitmun/sitmun-viewer-app/pull/202), [#203](https://github.com/sitmun/sitmun-viewer-app/pull/203)). - **Admin**: The stack points at admin `dev`, including the service-access clock and the cleanup that replaces filler expects, deletes unused task fields, corrects comments, drops local `any` casts, and removes narrating comments ([sitmun-admin-app#475](https://github.com/sitmun/sitmun-admin-app/pull/475), [#476](https://github.com/sitmun/sitmun-admin-app/pull/476), [#477](https://github.com/sitmun/sitmun-admin-app/pull/477), [#478](https://github.com/sitmun/sitmun-admin-app/pull/478), [#479](https://github.com/sitmun/sitmun-admin-app/pull/479), [#480](https://github.com/sitmun/sitmun-admin-app/pull/480)). - **Backend**: The stack points at backend `dev`. CI publishes `sitmun-shared` before the build. An LDAP login fails when the role lookup throws. Cleanup replaces filler expects, deletes unused symbols, and removes comments that name the wrong type or narrate the next line ([sitmun-backend-core#274](https://github.com/sitmun/sitmun-backend-core/pull/274), [#275](https://github.com/sitmun/sitmun-backend-core/pull/275), [#276](https://github.com/sitmun/sitmun-backend-core/pull/276), [#277](https://github.com/sitmun/sitmun-backend-core/pull/277), [#278](https://github.com/sitmun/sitmun-backend-core/pull/278), [#279](https://github.com/sitmun/sitmun-backend-core/pull/279), [#280](https://github.com/sitmun/sitmun-backend-core/pull/280), [#281](https://github.com/sitmun/sitmun-backend-core/pull/281)). diff --git a/README.md b/README.md index e104d61..8cb9d5e 100644 --- a/README.md +++ b/README.md @@ -548,7 +548,7 @@ Admin App ───┘ Root Playwright tests exercise the admin and viewer apps against backend-core on in-memory H2 (no Docker Compose). Viewer suite also starts proxy middleware and a local secured WMS stub. Mobile web suite covers edition Bearer login, proxy-token exchange, and authenticated MBTiles through middleware (no public `/mbtiles`). Details: [e2e/README.md](e2e/README.md). ```bash -# prerequisites: Java 17, Node ≥ 20.19, submodules initialized +# prerequisites: Java 17, Node ≥ 24.22.0 (mobile Android E2E needs Node 22), submodules initialized # admin: cd front/admin/sitmun-admin-app && npm ci # viewer: cd front/viewer/sitmun-viewer-app && npm ci npm ci @@ -1036,7 +1036,7 @@ rm -rf node_modules package-lock.json npm ci # Check Node.js version -node --version # Should be 20.19.0 or higher +node --version # Should be 24.22.0 or higher (Node 22 for mobile Android E2E) ``` #### Backend Build Issues diff --git a/back/backend/sitmun-backend-core b/back/backend/sitmun-backend-core index 0cd1495..a9349b8 160000 --- a/back/backend/sitmun-backend-core +++ b/back/backend/sitmun-backend-core @@ -1 +1 @@ -Subproject commit 0cd149521910f5c3b87309b36cc76f524b4b7efa +Subproject commit a9349b8cb26a82f079d188e7520b6eb7d76998f9 diff --git a/back/mbtiles/sitmun-mbtiles b/back/mbtiles/sitmun-mbtiles index 7417dca..609a807 160000 --- a/back/mbtiles/sitmun-mbtiles +++ b/back/mbtiles/sitmun-mbtiles @@ -1 +1 @@ -Subproject commit 7417dcaa7d705cf0f86b30e3a1c1bbc6f4bad489 +Subproject commit 609a807e98bc8f0bec5148ef6defba1a4fb86f28 diff --git a/back/proxy/sitmun-proxy-middleware b/back/proxy/sitmun-proxy-middleware index a05dd1b..05909bb 160000 --- a/back/proxy/sitmun-proxy-middleware +++ b/back/proxy/sitmun-proxy-middleware @@ -1 +1 @@ -Subproject commit a05dd1b5fdb8de67a9470bc576ede5e492e02a3e +Subproject commit 05909bb29e994ac6b69bed431320fddd97085172 diff --git a/back/shared/sitmun-shared b/back/shared/sitmun-shared index ca8d7e3..d900f42 160000 --- a/back/shared/sitmun-shared +++ b/back/shared/sitmun-shared @@ -1 +1 @@ -Subproject commit ca8d7e3ba9af05f30d1a3007808acffffe20cc7d +Subproject commit d900f42d8491aeff4cfb95da330a67d50bf52933 diff --git a/e2e/README.md b/e2e/README.md index e38edc3..8c43989 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -99,7 +99,7 @@ Shared H2 + admin + viewer + proxy + WMS stub. Do not run concurrently with admi ## Prerequisites - Java 17 -- Node ≥ 20.19 +- Node ≥ 24.22.0 (admin, viewer, and root web E2E). Mobile Android E2E needs Node 22. - Initialized submodules: `git submodule update --init --recursive` - Admin dependencies: `cd front/admin/sitmun-admin-app && npm ci` - Viewer dependencies: `cd front/viewer/sitmun-viewer-app && npm ci` diff --git a/front/Dockerfile b/front/Dockerfile index 9fc5e1c..11e626b 100644 --- a/front/Dockerfile +++ b/front/Dockerfile @@ -1,6 +1,6 @@ # Stage 0, "build-apps", based on Node.js, to build and compile both frontend apps sequentially # Each app's About-dialog version comes from its package.json at build time (not stack VERSION). -FROM node:20 AS build-apps +FROM node:24.22.0 AS build-apps ARG PUBLIC_BASE_PATH=/ ARG ENVIRONMENT=development ENV PUBLIC_BASE_PATH=${PUBLIC_BASE_PATH} @@ -49,7 +49,7 @@ COPY --chown=node:node front/viewer/index.html.template ./src/index.html.templat COPY --chown=node:node front/viewer/webpack.config.js.template ./webpack.config.js.template # Cap the viewer webpack heap so the build works when Docker VM RAM < 8 GiB. # Local npm run build uses 8192 MiB (the script default) when NODE_OPTIONS is unset. -ENV NODE_OPTIONS="--openssl-legacy-provider --max-old-space-size=4096" +ENV NODE_OPTIONS="--max-old-space-size=4096" RUN export BUILD_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") && \ export APP_VERSION=$(node -p "require('./package.json').version") && \ if [ "${ENVIRONMENT}" = "production" ]; then export FRONT_ENV=Production; export FRONT_PRODUCTION=true; else export FRONT_ENV=Development; export FRONT_PRODUCTION=false; fi && \ diff --git a/front/admin/sitmun-admin-app b/front/admin/sitmun-admin-app index d3ea569..c2175a5 160000 --- a/front/admin/sitmun-admin-app +++ b/front/admin/sitmun-admin-app @@ -1 +1 @@ -Subproject commit d3ea569aef1c5267a84021abbc0f9ef06eb232b9 +Subproject commit c2175a5675a4cdbec124c40e574daaab453d109b diff --git a/front/viewer/sitmun-viewer-app b/front/viewer/sitmun-viewer-app index 0f782d2..0b392f1 160000 --- a/front/viewer/sitmun-viewer-app +++ b/front/viewer/sitmun-viewer-app @@ -1 +1 @@ -Subproject commit 0f782d2467efc995e8bcbe66f8e96040bb9ca758 +Subproject commit 0b392f140869631027f3a6532ec8ea40944ae54a From d18701271dfa43deba99a639f7126dec7a901500 Mon Sep 17 00:00:00 2001 From: Francisco J Lopez-Pellicer Date: Tue, 20 Oct 2026 08:47:04 +0200 Subject: [PATCH 2/6] fix(ci): install viewer Node into nvm for E2E jobs e2e-viewer.mjs requires the exact .nvmrc binary under ~/.nvm; setup-node alone does not populate that path. --- .github/workflows/e2e.yml | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0eab7af..7de27d0 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -100,6 +100,22 @@ jobs: - name: Install Chromium run: npx playwright install --with-deps chromium + # scripts/e2e-viewer.mjs requires the exact viewer .nvmrc Node under ~/.nvm + # (actions/setup-node does not install into nvm). + - name: Install viewer Node into nvm + shell: bash + run: | + export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" + if [ ! -s "$NVM_DIR/nvm.sh" ]; then + curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash + fi + # shellcheck source=/dev/null + . "$NVM_DIR/nvm.sh" + VIEWER_NODE="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + VIEWER_NODE="${VIEWER_NODE#v}" + nvm install "$VIEWER_NODE" + test -x "$NVM_DIR/versions/node/v${VIEWER_NODE}/bin/node" + - name: Run viewer E2E suite run: npm run e2e:viewer env: @@ -160,6 +176,22 @@ jobs: - name: Install Chromium run: npx playwright install --with-deps chromium + # scripts/e2e-viewer.mjs requires the exact viewer .nvmrc Node under ~/.nvm + # (actions/setup-node does not install into nvm). + - name: Install viewer Node into nvm + shell: bash + run: | + export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" + if [ ! -s "$NVM_DIR/nvm.sh" ]; then + curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash + fi + # shellcheck source=/dev/null + . "$NVM_DIR/nvm.sh" + VIEWER_NODE="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + VIEWER_NODE="${VIEWER_NODE#v}" + nvm install "$VIEWER_NODE" + test -x "$NVM_DIR/versions/node/v${VIEWER_NODE}/bin/node" + - name: Run application-contact E2E suite run: npx playwright test --config=playwright.application-contact.config.ts env: @@ -220,6 +252,22 @@ jobs: - name: Install Chromium run: npx playwright install --with-deps chromium + # scripts/e2e-viewer.mjs requires the exact viewer .nvmrc Node under ~/.nvm + # (actions/setup-node does not install into nvm). + - name: Install viewer Node into nvm + shell: bash + run: | + export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" + if [ ! -s "$NVM_DIR/nvm.sh" ]; then + curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash + fi + # shellcheck source=/dev/null + . "$NVM_DIR/nvm.sh" + VIEWER_NODE="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + VIEWER_NODE="${VIEWER_NODE#v}" + nvm install "$VIEWER_NODE" + test -x "$NVM_DIR/versions/node/v${VIEWER_NODE}/bin/node" + - name: Run MIA cross E2E suite run: npm run e2e:mia-cross env: From 295b530604ca836e911368a08f9d4ca53efb71fe Mon Sep 17 00:00:00 2001 From: Francisco J Lopez-Pellicer Date: Tue, 20 Oct 2026 08:51:41 +0200 Subject: [PATCH 3/6] fix(ci): use dcodeIO/setup-node-nvm for viewer E2E Replace the shell nvm install on viewer/contact/mia-cross with dcodeIO/setup-node-nvm@v5. Symlink $HOME/mynvm to ~/.nvm so e2e-viewer.mjs keeps its exact-path gate. --- .github/workflows/e2e.yml | 78 ++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 7de27d0..8a21657 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -100,21 +100,19 @@ jobs: - name: Install Chromium run: npx playwright install --with-deps chromium - # scripts/e2e-viewer.mjs requires the exact viewer .nvmrc Node under ~/.nvm - # (actions/setup-node does not install into nvm). - - name: Install viewer Node into nvm - shell: bash + # e2e-viewer.mjs requires ~/.nvm/versions/node/v/bin (setup-node does not). + # dcodeIO/setup-node-nvm installs into $HOME/mynvm; link that tree to ~/.nvm. + - name: Read viewer .nvmrc + id: viewer-nvmrc run: | - export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" - if [ ! -s "$NVM_DIR/nvm.sh" ]; then - curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash - fi - # shellcheck source=/dev/null - . "$NVM_DIR/nvm.sh" - VIEWER_NODE="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" - VIEWER_NODE="${VIEWER_NODE#v}" - nvm install "$VIEWER_NODE" - test -x "$NVM_DIR/versions/node/v${VIEWER_NODE}/bin/node" + ver="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + echo "version=${ver#v}" >> "$GITHUB_OUTPUT" + - name: Install viewer Node into nvm + uses: dcodeIO/setup-node-nvm@v5 + with: + node-version: ${{ steps.viewer-nvmrc.outputs.version }} + - name: Point ~/.nvm at setup-node-nvm install + run: ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" - name: Run viewer E2E suite run: npm run e2e:viewer @@ -176,21 +174,19 @@ jobs: - name: Install Chromium run: npx playwright install --with-deps chromium - # scripts/e2e-viewer.mjs requires the exact viewer .nvmrc Node under ~/.nvm - # (actions/setup-node does not install into nvm). - - name: Install viewer Node into nvm - shell: bash + # e2e-viewer.mjs requires ~/.nvm/versions/node/v/bin (setup-node does not). + # dcodeIO/setup-node-nvm installs into $HOME/mynvm; link that tree to ~/.nvm. + - name: Read viewer .nvmrc + id: viewer-nvmrc run: | - export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" - if [ ! -s "$NVM_DIR/nvm.sh" ]; then - curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash - fi - # shellcheck source=/dev/null - . "$NVM_DIR/nvm.sh" - VIEWER_NODE="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" - VIEWER_NODE="${VIEWER_NODE#v}" - nvm install "$VIEWER_NODE" - test -x "$NVM_DIR/versions/node/v${VIEWER_NODE}/bin/node" + ver="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + echo "version=${ver#v}" >> "$GITHUB_OUTPUT" + - name: Install viewer Node into nvm + uses: dcodeIO/setup-node-nvm@v5 + with: + node-version: ${{ steps.viewer-nvmrc.outputs.version }} + - name: Point ~/.nvm at setup-node-nvm install + run: ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" - name: Run application-contact E2E suite run: npx playwright test --config=playwright.application-contact.config.ts @@ -252,21 +248,19 @@ jobs: - name: Install Chromium run: npx playwright install --with-deps chromium - # scripts/e2e-viewer.mjs requires the exact viewer .nvmrc Node under ~/.nvm - # (actions/setup-node does not install into nvm). - - name: Install viewer Node into nvm - shell: bash + # e2e-viewer.mjs requires ~/.nvm/versions/node/v/bin (setup-node does not). + # dcodeIO/setup-node-nvm installs into $HOME/mynvm; link that tree to ~/.nvm. + - name: Read viewer .nvmrc + id: viewer-nvmrc run: | - export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" - if [ ! -s "$NVM_DIR/nvm.sh" ]; then - curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash - fi - # shellcheck source=/dev/null - . "$NVM_DIR/nvm.sh" - VIEWER_NODE="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" - VIEWER_NODE="${VIEWER_NODE#v}" - nvm install "$VIEWER_NODE" - test -x "$NVM_DIR/versions/node/v${VIEWER_NODE}/bin/node" + ver="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + echo "version=${ver#v}" >> "$GITHUB_OUTPUT" + - name: Install viewer Node into nvm + uses: dcodeIO/setup-node-nvm@v5 + with: + node-version: ${{ steps.viewer-nvmrc.outputs.version }} + - name: Point ~/.nvm at setup-node-nvm install + run: ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" - name: Run MIA cross E2E suite run: npm run e2e:mia-cross From a087a33cf49d712f569d17345afe57b9b0a4a259 Mon Sep 17 00:00:00 2001 From: Francisco J Lopez-Pellicer Date: Tue, 20 Oct 2026 10:45:53 +0200 Subject: [PATCH 4/6] fix(e2e): nvm path, Boot/Angular admin regressions, cartography list oracle Replace nested ~/.nvm symlink so viewer jobs find Node 24. Point admin and backend at AG Grid 32 editor + language URL and Hibernate 7 cartography EntityGraph fixes. Add cartography-list e2e for the MIA blank-form gap. --- .github/workflows/e2e.yml | 30 +++++++++++++++++++++--- back/backend/sitmun-backend-core | 2 +- e2e/README.md | 1 + e2e/admin/forms/cartography-list.spec.ts | 17 ++++++++++++++ front/admin/sitmun-admin-app | 2 +- 5 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 e2e/admin/forms/cartography-list.spec.ts diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 8a21657..e6b6609 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -112,7 +112,15 @@ jobs: with: node-version: ${{ steps.viewer-nvmrc.outputs.version }} - name: Point ~/.nvm at setup-node-nvm install - run: ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" + run: | + # Ubuntu runners often ship ~/.nvm as a real directory; ln -sfn into a + # directory nests the link. Replace it so e2e-viewer.mjs finds node. + echo "NVM_DIR=${HOME}/mynvm" >> "$GITHUB_ENV" + rm -rf "${HOME}/.nvm" + ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" + ver="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + ver="${ver#v}" + test -x "${HOME}/.nvm/versions/node/v${ver}/bin/node" - name: Run viewer E2E suite run: npm run e2e:viewer @@ -186,7 +194,15 @@ jobs: with: node-version: ${{ steps.viewer-nvmrc.outputs.version }} - name: Point ~/.nvm at setup-node-nvm install - run: ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" + run: | + # Ubuntu runners often ship ~/.nvm as a real directory; ln -sfn into a + # directory nests the link. Replace it so e2e-viewer.mjs finds node. + echo "NVM_DIR=${HOME}/mynvm" >> "$GITHUB_ENV" + rm -rf "${HOME}/.nvm" + ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" + ver="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + ver="${ver#v}" + test -x "${HOME}/.nvm/versions/node/v${ver}/bin/node" - name: Run application-contact E2E suite run: npx playwright test --config=playwright.application-contact.config.ts @@ -260,7 +276,15 @@ jobs: with: node-version: ${{ steps.viewer-nvmrc.outputs.version }} - name: Point ~/.nvm at setup-node-nvm install - run: ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" + run: | + # Ubuntu runners often ship ~/.nvm as a real directory; ln -sfn into a + # directory nests the link. Replace it so e2e-viewer.mjs finds node. + echo "NVM_DIR=${HOME}/mynvm" >> "$GITHUB_ENV" + rm -rf "${HOME}/.nvm" + ln -sfn "${HOME}/mynvm" "${HOME}/.nvm" + ver="$(tr -d '[:space:]' < front/viewer/sitmun-viewer-app/.nvmrc)" + ver="${ver#v}" + test -x "${HOME}/.nvm/versions/node/v${ver}/bin/node" - name: Run MIA cross E2E suite run: npm run e2e:mia-cross diff --git a/back/backend/sitmun-backend-core b/back/backend/sitmun-backend-core index a9349b8..374e1bb 160000 --- a/back/backend/sitmun-backend-core +++ b/back/backend/sitmun-backend-core @@ -1 +1 @@ -Subproject commit a9349b8cb26a82f079d188e7520b6eb7d76998f9 +Subproject commit 374e1bbea52cc3e9f5daec4692187fbcf5b1babb diff --git a/e2e/README.md b/e2e/README.md index 8c43989..8d7b778 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -24,6 +24,7 @@ Browser E2E against backend-core on in-memory H2. No Docker Compose. - Plantilla role and territory tabs: assigning a role and a territory on the task form persists after reload ([sitmun-admin-app#467](https://github.com/sitmun/sitmun-admin-app/issues/467); `e2e/admin/forms/template-task-relations.spec.ts`, project `admin-forms`) - More Info Advanced **Details**: validation, create with cartography + included query child 38, layout update persistence; cartography open-in-new; deep route `/#/tasks/42/16`; Parameters `app-relation-grid` add + reload persist; child parameter mapping UI round-trip + persists across a subsequent Parameters save; orphan `childTaskParameters` keys dropped on save; Add mapping disabled when included child has no parameters; ADMIN `POST /api/tasks/template/more-info-advanced/render` for seeded parent 42 (`e2e/admin/forms/mia-form.spec.ts`, project `admin-forms`) +- Cartography collection: ADMIN `GET /api/cartographies?size=10000` returns 200 (Boot 4.1.1 / Hibernate 7 EntityGraph+styles bag regression that blanked MIA cartography autocomplete) (`e2e/admin/forms/cartography-list.spec.ts`, project `admin-forms`) - Language default change: Set as Default preview dialog cancel leaves `language.default` unchanged; raw config PUT cannot freely replace it (`e2e/admin/forms/language-default.spec.ts`) - Language enabled/order: disable/reorder a non-default language, assert login chrome omits it, restore (`e2e/admin/forms/language-order.spec.ts`) - Literal translations grid CRUD (not `app-relation-grid`; no CSV): create row and reload persists (`e2e/admin/forms/literal-translation-form.spec.ts`) diff --git a/e2e/admin/forms/cartography-list.spec.ts b/e2e/admin/forms/cartography-list.spec.ts new file mode 100644 index 0000000..b3d1a3f --- /dev/null +++ b/e2e/admin/forms/cartography-list.spec.ts @@ -0,0 +1,17 @@ +import { test, expect } from '../fixtures'; + +/** + * Boot 4.1.1 / Hibernate 7 regression: paged cartography list with EntityGraph+styles bag + * returned 500, which blanked MIA (and other) forms that call fetchAllRawItems(size=10000). + */ +test.describe('Cartography collection list', () => { + test('GET /api/cartographies?size=10000 returns 200 for admin', async ({ request }) => { + const response = await request.get('/backend/api/cartographies?size=10000', { + headers: { 'X-SITMUN-Client': 'admin' }, + }); + expect(response.status(), await response.text()).toBe(200); + const body = await response.json(); + const items = body?._embedded?.cartographies ?? body; + expect(Array.isArray(items) ? items.length : 0).toBeGreaterThan(0); + }); +}); diff --git a/front/admin/sitmun-admin-app b/front/admin/sitmun-admin-app index c2175a5..5abc705 160000 --- a/front/admin/sitmun-admin-app +++ b/front/admin/sitmun-admin-app @@ -1 +1 @@ -Subproject commit c2175a5675a4cdbec124c40e574daaab453d109b +Subproject commit 5abc70512263a3b5fdc1e9a0cacaf2cb6dbbdebd From ddc6a2a01e382931ebb3b04da652e52db50ae2ae Mon Sep 17 00:00:00 2001 From: Francisco J Lopez-Pellicer Date: Tue, 20 Oct 2026 11:10:49 +0200 Subject: [PATCH 5/6] fix(e2e): Instant-safe datePicker pointer and Baja edit oracle Point admin at 8bcd38f4 so Positions Alta/Baja inline edit survives AG Grid 32 DataTypeModule. Cover the Baja sibling of the Alta Instant ISO editor crash. --- e2e/README.md | 2 +- e2e/admin/forms/user-positions.spec.ts | 19 +++++++++++++++++++ e2e/admin/helpers/user-positions.ts | 16 ++++++++++++++-- front/admin/sitmun-admin-app | 2 +- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/e2e/README.md b/e2e/README.md index 8d7b778..242a772 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -10,7 +10,7 @@ Browser E2E against backend-core on in-memory H2. No Docker Compose. - Language chrome on login: cleared `lang` → closed BCP-47 ISO from `language.default`; open menu shows API endonyms; no language field on the login form (`e2e/admin/language-chrome.spec.ts`, project `login`) - Role form **Details**: validation, create, edit, reload persistence (relation tabs not exercised) - User form **Details**: validation, create, edit, reload persistence (relation tabs not exercised) -- User form **Positions**: `Valid from` immediately before `Valid until` (ES `Fecha de alta` / `Fecha de baja`); empty `createdDate` is Not set / No informada; empty `expirationDate` is Active; Alta edit persist; inclusive last-day tooltip; hidden for `public`; pre-2000 Alta cell; viewer cannot write Alta; 20-row open under 3s ([sitmun-admin-app#462](https://github.com/sitmun/sitmun-admin-app/issues/462); `e2e/admin/forms/user-positions.spec.ts`, project `admin-forms`) +- User form **Positions**: `Valid from` immediately before `Valid until` (ES `Fecha de alta` / `Fecha de baja`); empty `createdDate` is Not set / No informada; empty `expirationDate` is Active; Alta and Baja edit persist; inclusive last-day tooltip; hidden for `public`; pre-2000 Alta cell; viewer cannot write Alta; 20-row open under 3s ([sitmun-admin-app#462](https://github.com/sitmun/sitmun-admin-app/issues/462); `e2e/admin/forms/user-positions.spec.ts`, project `admin-forms`) - Territory form **Details**: validation, create (with type), edit, reload persistence (relation tabs not exercised) - Tree form **Details** SVG local-file persist and touristic **Tree structure** node Appearance SVG persist: picker `accept` includes `.svg`; POST/PUT stores `data:image/svg+xml;base64,...` without raster scaling; reload preview stays SVG ([sitmun-admin-app#330](https://github.com/sitmun/sitmun-admin-app/issues/330); `e2e/admin/forms/tree-svg-image.spec.ts`, project `admin-forms`) - Layers form **Details**: validation, create, reload persistence; Feature Information character-count must not throw `raw.split` beside the queryable-layers CSV validator (`e2e/admin/forms/layers-form.spec.ts`, project `admin-forms`) diff --git a/e2e/admin/forms/user-positions.spec.ts b/e2e/admin/forms/user-positions.spec.ts index d7d1801..fdad78c 100644 --- a/e2e/admin/forms/user-positions.spec.ts +++ b/e2e/admin/forms/user-positions.spec.ts @@ -11,6 +11,7 @@ import { POSITIONS_TAB, createUserViaForm, editAltaCell, + editBajaCell, expectCreatedThenExpiration, headerTexts, openPositions, @@ -69,6 +70,24 @@ test.describe('User Positions tab', () => { await saveShot(page, 'admin-edit-alta.png'); }); + // Sibling of Alta edit: same Instant ISO + datePicker path on expirationDate. + test('edits Baja and it persists after reload', async ({ page, request, createdResources }) => { + const { id } = await createUserViaForm(page, 'e2ebajaedt'); + createdResources.push({ collection: 'users', id }); + await postPosition(request, id, { expirationDate: '2030-12-31T00:00:00.000Z' }); + + await openPositions(page, id); + await editBajaCell(page, '2028-07-04'); + await savePositionUpdate(page); + + await page.reload(); + await openPositions(page, id); + await expect( + page.locator('app-relation-grid .ag-cell[col-id="expirationDate"]').first(), + ).toContainText(/2028/); + await saveShot(page, 'admin-edit-baja.png'); + }); + test('Baja header tooltip states the inclusive last civil day', async ({ page, request, diff --git a/e2e/admin/helpers/user-positions.ts b/e2e/admin/helpers/user-positions.ts index 7036acb..2020e87 100644 --- a/e2e/admin/helpers/user-positions.ts +++ b/e2e/admin/helpers/user-positions.ts @@ -123,8 +123,12 @@ export async function saveShot(page: Page, name: string): Promise { await page.screenshot({ path: `test-results/${name}` }); } -export async function editAltaCell(page: Page, isoDate: string): Promise { - const cell = page.locator('app-relation-grid .ag-cell[col-id="createdDate"]').first(); +export async function editDateCell( + page: Page, + colId: 'createdDate' | 'expirationDate', + isoDate: string, +): Promise { + const cell = page.locator(`app-relation-grid .ag-cell[col-id="${colId}"]`).first(); await expect(cell).toBeVisible({ timeout: 15_000 }); await cell.dblclick(); const editor = page.locator('app-relation-grid .ag-cell-inline-editing input').first(); @@ -139,6 +143,14 @@ export async function editAltaCell(page: Page, isoDate: string): Promise { await page.keyboard.press('Enter'); } +export async function editAltaCell(page: Page, isoDate: string): Promise { + await editDateCell(page, 'createdDate', isoDate); +} + +export async function editBajaCell(page: Page, isoDate: string): Promise { + await editDateCell(page, 'expirationDate', isoDate); +} + export async function savePositionUpdate(page: Page): Promise { const putResponse = page.waitForResponse((response) => { try { diff --git a/front/admin/sitmun-admin-app b/front/admin/sitmun-admin-app index 5abc705..8bcd38f 160000 --- a/front/admin/sitmun-admin-app +++ b/front/admin/sitmun-admin-app @@ -1 +1 @@ -Subproject commit 5abc70512263a3b5fdc1e9a0cacaf2cb6dbbdebd +Subproject commit 8bcd38f468995f2430c9dc875633b3799e019b9a From c645b87308d8ed510f66d5f762fcf5de4f509a04 Mon Sep 17 00:00:00 2001 From: Francisco J Lopez-Pellicer Date: Tue, 20 Oct 2026 11:13:37 +0200 Subject: [PATCH 6/6] test(e2e): cover Positions text editor sibling of Alta/Baja Oracle that CommunityFeaturesModule text inline edit on Position name persists, the sibling path the Instant datePicker crash did not cover. --- e2e/README.md | 2 +- e2e/admin/forms/user-positions.spec.ts | 22 ++++++++++++++++++++++ e2e/admin/helpers/user-positions.ts | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/e2e/README.md b/e2e/README.md index 242a772..ba9042e 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -10,7 +10,7 @@ Browser E2E against backend-core on in-memory H2. No Docker Compose. - Language chrome on login: cleared `lang` → closed BCP-47 ISO from `language.default`; open menu shows API endonyms; no language field on the login form (`e2e/admin/language-chrome.spec.ts`, project `login`) - Role form **Details**: validation, create, edit, reload persistence (relation tabs not exercised) - User form **Details**: validation, create, edit, reload persistence (relation tabs not exercised) -- User form **Positions**: `Valid from` immediately before `Valid until` (ES `Fecha de alta` / `Fecha de baja`); empty `createdDate` is Not set / No informada; empty `expirationDate` is Active; Alta and Baja edit persist; inclusive last-day tooltip; hidden for `public`; pre-2000 Alta cell; viewer cannot write Alta; 20-row open under 3s ([sitmun-admin-app#462](https://github.com/sitmun/sitmun-admin-app/issues/462); `e2e/admin/forms/user-positions.spec.ts`, project `admin-forms`) +- User form **Positions**: `Valid from` immediately before `Valid until` (ES `Fecha de alta` / `Fecha de baja`); empty `createdDate` is Not set / No informada; empty `expirationDate` is Active; Alta and Baja edit persist; Position name text edit persist; inclusive last-day tooltip; hidden for `public`; pre-2000 Alta cell; viewer cannot write Alta; 20-row open under 3s ([sitmun-admin-app#462](https://github.com/sitmun/sitmun-admin-app/issues/462); `e2e/admin/forms/user-positions.spec.ts`, project `admin-forms`) - Territory form **Details**: validation, create (with type), edit, reload persistence (relation tabs not exercised) - Tree form **Details** SVG local-file persist and touristic **Tree structure** node Appearance SVG persist: picker `accept` includes `.svg`; POST/PUT stores `data:image/svg+xml;base64,...` without raster scaling; reload preview stays SVG ([sitmun-admin-app#330](https://github.com/sitmun/sitmun-admin-app/issues/330); `e2e/admin/forms/tree-svg-image.spec.ts`, project `admin-forms`) - Layers form **Details**: validation, create, reload persistence; Feature Information character-count must not throw `raw.split` beside the queryable-layers CSV validator (`e2e/admin/forms/layers-form.spec.ts`, project `admin-forms`) diff --git a/e2e/admin/forms/user-positions.spec.ts b/e2e/admin/forms/user-positions.spec.ts index fdad78c..92cf216 100644 --- a/e2e/admin/forms/user-positions.spec.ts +++ b/e2e/admin/forms/user-positions.spec.ts @@ -12,6 +12,7 @@ import { createUserViaForm, editAltaCell, editBajaCell, + editPositionNameCell, expectCreatedThenExpiration, headerTexts, openPositions, @@ -88,6 +89,27 @@ test.describe('User Positions tab', () => { await saveShot(page, 'admin-edit-baja.png'); }); + // Sibling: CommunityFeaturesModule text editor on the same Positions grid. + test('edits Position name and it persists after reload', async ({ + page, + request, + createdResources, + }) => { + const { id } = await createUserViaForm(page, 'e2eposn'); + createdResources.push({ collection: 'users', id }); + await postPosition(request, id, { name: 'Cargo' }); + + await openPositions(page, id); + await editPositionNameCell(page, 'Cargo editado'); + await savePositionUpdate(page); + + await page.reload(); + await openPositions(page, id); + await expect(page.locator('app-relation-grid .ag-cell[col-id="name"]').first()).toContainText( + 'Cargo editado', + ); + }); + test('Baja header tooltip states the inclusive last civil day', async ({ page, request, diff --git a/e2e/admin/helpers/user-positions.ts b/e2e/admin/helpers/user-positions.ts index 2020e87..e543e9a 100644 --- a/e2e/admin/helpers/user-positions.ts +++ b/e2e/admin/helpers/user-positions.ts @@ -151,6 +151,23 @@ export async function editBajaCell(page: Page, isoDate: string): Promise { await editDateCell(page, 'expirationDate', isoDate); } +/** Inline text editor on Position name (CommunityFeaturesModule text path). */ +export async function editPositionNameCell(page: Page, name: string): Promise { + const cell = page.locator('app-relation-grid .ag-cell[col-id="name"]').first(); + await expect(cell).toBeVisible({ timeout: 15_000 }); + await cell.dblclick(); + const editor = page.locator('app-relation-grid .ag-cell-inline-editing input').first(); + if ((await editor.count()) === 0 || !(await editor.isVisible())) { + await cell.click(); + await page.keyboard.press('F2'); + } + await expect(page.locator('app-relation-grid .ag-cell-inline-editing input').first()).toBeVisible({ + timeout: 5_000, + }); + await page.locator('app-relation-grid .ag-cell-inline-editing input').first().fill(name); + await page.keyboard.press('Enter'); +} + export async function savePositionUpdate(page: Page): Promise { const putResponse = page.waitForResponse((response) => { try {