From 2e894dba7d0a760649289a9fd89bf27e12b47c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Storl=C3=B8kken=20Melseth?= Date: Thu, 28 May 2026 10:37:13 +0000 Subject: [PATCH 1/6] chore: dev container --- .devcontainer/Dockerfile | 17 ++++++++++++ .devcontainer/devcontainer-lock.json | 9 +++++++ .devcontainer/devcontainer.json | 36 +++++++++++++++++++++++++ .devcontainer/docker-compose.yml | 16 +++++++++++ .gitignore | 5 +++- i18n/en.pot | 4 +-- package.json | 4 +-- scripts/clean.sh | 2 +- scripts/package/cy-open-devcontainer.sh | 11 ++++++++ scripts/package/cy-open-local.sh | 5 ++++ scripts/package/cy-run.sh | 5 ++++ 11 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer-lock.json create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/docker-compose.yml create mode 100755 scripts/package/cy-open-devcontainer.sh create mode 100755 scripts/package/cy-open-local.sh create mode 100755 scripts/package/cy-run.sh diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000..3fe7b57f60 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,17 @@ +FROM mcr.microsoft.com/devcontainers/base:trixie + +RUN apt-get update && apt-get install -y \ + libgtk2.0-0 \ + libgtk-3-0 \ + libgbm-dev \ + libnotify-dev \ + libnss3 \ + libxss1 \ + libasound2t64 \ + libxtst6 \ + xauth \ + xvfb \ + x11vnc \ + novnc \ + openbox \ + && rm -rf /var/lib/apt/lists/* \ No newline at end of file diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 0000000000..613e724f48 --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,9 @@ +{ + "features": { + "ghcr.io/devcontainers/features/node:2": { + "version": "2.0.0", + "resolved": "ghcr.io/devcontainers/features/node@sha256:fedd4c11f7adfb64283b578dddc7da906728daa25fa293351c9d913231acf12f", + "integrity": "sha256:fedd4c11f7adfb64283b578dddc7da906728daa25fa293351c9d913231acf12f" + } + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..bddf23b26a --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "capture-app-dev", + "dockerComposeFile": ["docker-compose.yml", "docker-compose.override.yml"], + "service": "dev", + "workspaceFolder": "/workspaces/capture-app", + "features": { + "ghcr.io/devcontainers/features/node:2": { + "nodeGypDependencies": true, + "installYarnUsingApt": true, + "version": "22.22.3", + "npmVersion": "11.15.0", + "pnpmVersion": "11.2.2", + "nvmVersion": "0.40.4" + } + }, + "portsAttributes": { + "3000": { "onAutoForward": "notify" }, + "6080": { "onAutoForward": "notify" } + }, + "otherPortsAttributes": { "onAutoForward": "ignore" }, + "remoteEnv": { "IN_DEVCONTAINER": "true" }, + "postCreateCommand": "sudo chown -R $(id -u):$(id -g) /workspaces/capture-app/node_modules /home/vscode/.cache && curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh && echo '{\"minimumPackageAgeHours\": 120, \"yarn\": {\"minimumPackageAgeExclusions\": [\"@dhis2/*\"]}}' > ~/.safe-chain/config.json", + "customizations": { + "vscode": { + "extensions": [ + "Anthropic.claude-code@2.1.145", + "waderyan.gitblame@13.0.1", + "mhutchie.git-graph@1.30.0", + "esbenp.prettier-vscode@12.4.0", + "mxsdev.typescript-explorer@0.4.2" + ] + } + } +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000000..f087d952ea --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,16 @@ +services: + dev: + build: + context: . + dockerfile: Dockerfile + volumes: + - ..:/workspaces/capture-app:cached + - node_modules:/workspaces/capture-app/node_modules + - yarn_cache:/home/vscode/.cache/yarn + - cypress_cache:/home/vscode/.cache/Cypress + command: sleep infinity + +volumes: + node_modules: + yarn_cache: + cypress_cache: diff --git a/.gitignore b/.gitignore index 3b6fa70eb9..aaba1c1166 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,7 @@ src/locales/ # Cursor .cursorrules -.cursor \ No newline at end of file +.cursor + +# local devcontainer overrides +.devcontainer/docker-compose.override.yml \ No newline at end of file diff --git a/i18n/en.pot b/i18n/en.pot index 58ea419d37..00f2c668d3 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2026-05-26T07:35:44.230Z\n" -"PO-Revision-Date: 2026-05-26T07:35:44.230Z\n" +"POT-Creation-Date: 2026-05-28T10:37:18.094Z\n" +"PO-Revision-Date: 2026-05-28T10:37:18.094Z\n" msgid "The application could not be loaded." msgstr "The application could not be loaded." diff --git a/package.json b/package.json index a888c17cf9..460e333924 100644 --- a/package.json +++ b/package.json @@ -74,8 +74,8 @@ "jsdoc": "NODE_ENV=development jsdoc -c jsdoc-conf.json", "linter:check": "yarn workspaces run linter:check && yarn workspaces run build && eslint -c .eslintrc . --quiet", "tsc:check": "./node_modules/.bin/tsc --noEmit && yarn workspaces run tsc:check", - "cy:open": "export NODE_OPTIONS=--openssl-legacy-provider && concurrently --kill-others \"yarn start:forCypress\" \"wait-on 'http-get://127.0.0.1:3000' && cypress open\"", - "cy:run": "export NODE_OPTIONS=--openssl-legacy-provider && concurrently --kill-others \"yarn start:forCypress\" \"wait-on 'http-get://127.0.0.1:3000' && cypress run\"", + "cy:open": "[ \"$IN_DEVCONTAINER\" = \"true\" ] && ./scripts/package/cy-open-devcontainer.sh || ./scripts/package/cy-open-local.sh", + "cy:run": "./scripts/package/cy-run.sh", "verifyCacheVersion": "node scripts/verifyCacheVersion.js", "postinstall": "husky && node scripts/createSymlinkToInternalPackages.mjs", "i18n:add": "d2-app-scripts i18n extract && git add ./i18n/", diff --git a/scripts/clean.sh b/scripts/clean.sh index 15bb7cab70..dceb6d6b3d 100755 --- a/scripts/clean.sh +++ b/scripts/clean.sh @@ -3,4 +3,4 @@ echo " - Removing generated project folders..." rm -rf .d2 rm -rf build -rm -rf node_modules +rm -rf node_modules/* node_modules/.[!.]* node_modules/..?* diff --git a/scripts/package/cy-open-devcontainer.sh b/scripts/package/cy-open-devcontainer.sh new file mode 100755 index 0000000000..1f3e8059fa --- /dev/null +++ b/scripts/package/cy-open-devcontainer.sh @@ -0,0 +1,11 @@ +#!/bin/bash +export NODE_OPTIONS=--openssl-legacy-provider +export DISPLAY=:99 +concurrently --kill-others \ + "Xvfb :99 -screen 0 1920x1080x24 -ac -listen tcp" \ + "wait-on tcp:localhost:6099 && openbox" \ + "wait-on tcp:localhost:6099 && x11vnc -display :99 -forever -nopw -quiet -rfbport 5900" \ + "/usr/share/novnc/utils/novnc_proxy --vnc localhost:5900 --listen 6080" \ + "yarn start:forCypress" \ + "wait-on 'http-get://127.0.0.1:3000' tcp:localhost:6099 && cypress open" \ + "wait-on 'http-get://127.0.0.1:3000' tcp:localhost:6099 && until pgrep -f '.cache/Cypress' > /dev/null 2>&1; do sleep 0.5; done && echo 'Cypress interface: http://localhost:6080/vnc.html' && sleep infinity" diff --git a/scripts/package/cy-open-local.sh b/scripts/package/cy-open-local.sh new file mode 100755 index 0000000000..64e347598c --- /dev/null +++ b/scripts/package/cy-open-local.sh @@ -0,0 +1,5 @@ +#!/bin/bash +export NODE_OPTIONS=--openssl-legacy-provider +concurrently --kill-others \ + "yarn start:forCypress" \ + "wait-on 'http-get://127.0.0.1:3000' && cypress open" diff --git a/scripts/package/cy-run.sh b/scripts/package/cy-run.sh new file mode 100755 index 0000000000..8f10776e7c --- /dev/null +++ b/scripts/package/cy-run.sh @@ -0,0 +1,5 @@ +#!/bin/bash +export NODE_OPTIONS=--openssl-legacy-provider +concurrently --kill-others \ + "yarn start:forCypress" \ + "wait-on 'http-get://127.0.0.1:3000' && cypress run" From 49cd1d1849ef8026448e5b3c9129ba2c9f7844a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Storl=C3=B8kken=20Melseth?= Date: Thu, 28 May 2026 12:04:06 +0000 Subject: [PATCH 2/6] chore: update workflows --- .github/workflows/dhis2-verify-commits.yml | 32 ++++++++++--- .github/workflows/e2e-tests.yml | 21 +++++++++ .github/workflows/preview.yml | 12 ++++- .github/workflows/verify-app.yml | 52 +++++++++++++++++----- 4 files changed, 97 insertions(+), 20 deletions(-) diff --git a/.github/workflows/dhis2-verify-commits.yml b/.github/workflows/dhis2-verify-commits.yml index c036bb62d2..cbdea9189c 100644 --- a/.github/workflows/dhis2-verify-commits.yml +++ b/.github/workflows/dhis2-verify-commits.yml @@ -16,9 +16,19 @@ jobs: - uses: actions/cache@v4 id: yarn-cache with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - - run: yarn install --frozen-lockfile + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - name: Install safe-chain + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci + - name: Install + if: steps.yarn-cache.outputs.cache-hit != 'true' + env: + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" + run: yarn install --frozen-lockfile - id: commitlint run: echo ::set-output name=config_path::$(node -e "process.stdout.write(require('@dhis2/cli-style').config.commitlint)") - uses: JulienKode/pull-request-name-linter-action@v0.5.0 @@ -38,9 +48,19 @@ jobs: - uses: actions/cache@v4 id: yarn-cache with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - - run: yarn install --frozen-lockfile + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - name: Install safe-chain + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci + - name: Install + if: steps.yarn-cache.outputs.cache-hit != 'true' + env: + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" + run: yarn install --frozen-lockfile - id: commitlint run: echo ::set-output name=config_path::$(node -e "process.stdout.write(require('@dhis2/cli-style').config.commitlint)") - uses: wagoid/commitlint-github-action@v4 diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 835be7338c..f638c4f9f2 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -118,9 +118,30 @@ jobs: echo "Computed Tag=${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_TAG || '' }}" echo "Computed CI Build ID=${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_CI_BUILD_ID || '' }}" echo "Spec=${{ join(matrix.spec-group.tests, ',') }}" + + - uses: actions/cache@v4 + id: yarn-cache + with: + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + + - name: Install safe-chain + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci + + - name: Install + if: steps.yarn-cache.outputs.cache-hit != 'true' + env: + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" + run: yarn install --frozen-lockfile + - name: Cypress run uses: cypress-io/github-action@v6 with: + install: false record: ${{ env.SHOULD_RECORD }} parallel: ${{ env.SHOULD_RECORD }} group: ${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_GROUP || '' }} diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 0df4f3a4bf..2623b1c861 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -17,11 +17,19 @@ jobs: - uses: actions/cache@v4 id: yarn-cache with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - name: Install safe-chain + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci - name: Install if: steps.yarn-cache.outputs.cache-hit != 'true' + env: + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" run: yarn install --frozen-lockfile - name: Build diff --git a/.github/workflows/verify-app.yml b/.github/workflows/verify-app.yml index cd237479e8..71237e9e9d 100644 --- a/.github/workflows/verify-app.yml +++ b/.github/workflows/verify-app.yml @@ -28,11 +28,20 @@ jobs: - uses: actions/cache@v4 id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + + - name: Install safe-chain + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci - name: Install if: steps.yarn-cache.outputs.cache-hit != 'true' + env: + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" run: yarn install --frozen-lockfile lint: @@ -48,8 +57,10 @@ jobs: - uses: actions/cache@v4 id: yarn-cache with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - name: Lint run: yarn linter:check @@ -67,8 +78,10 @@ jobs: - uses: actions/cache@v4 id: yarn-cache with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - name: TypeScript run: yarn tsc:check @@ -86,8 +99,10 @@ jobs: - uses: actions/cache@v4 id: yarn-cache with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - name: Unit tests run: yarn test @@ -150,9 +165,18 @@ jobs: echo "Computed CI Build ID=${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_CI_BUILD_ID || '' }}" echo "Spec=${{ join(matrix.spec-group.tests, ',') }}" + - uses: actions/cache@v4 + id: yarn-cache + with: + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - name: Cypress run uses: cypress-io/github-action@v6 with: + install: false record: ${{ env.SHOULD_RECORD }} parallel: ${{ env.SHOULD_RECORD }} group: ${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_GROUP || '' }} @@ -188,8 +212,10 @@ jobs: - uses: actions/cache@v4 id: yarn-cache with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - name: Build run: yarn build @@ -222,8 +248,10 @@ jobs: - uses: actions/cache@v4 id: yarn-cache with: - path: '**/node_modules' - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + path: | + **/node_modules + ~/.cache/Cypress + key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - uses: dhis2/action-semantic-release@use-yarn-version-prepare with: From 8c8157448ac1596ad1c0a377554562c25d8d9f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Storl=C3=B8kken=20Melseth?= Date: Mon, 1 Jun 2026 04:06:48 +0000 Subject: [PATCH 3/6] chore: workflow ups --- .devcontainer/devcontainer.json | 6 +- .../safe-yarn-install-using-cache/action.yml | 36 ++++++ .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/dhis2-verify-commits.yml | 46 ++----- .github/workflows/e2e-tests.yml | 29 +---- .github/workflows/preview.yml | 24 +--- .github/workflows/verify-app.yml | 115 +++++------------- .nvmrc | 1 + i18n/en.pot | 4 +- 9 files changed, 92 insertions(+), 171 deletions(-) create mode 100644 .github/actions/safe-yarn-install-using-cache/action.yml create mode 100644 .nvmrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index bddf23b26a..c1be54bc9f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -9,9 +9,9 @@ "ghcr.io/devcontainers/features/node:2": { "nodeGypDependencies": true, "installYarnUsingApt": true, - "version": "22.22.3", - "npmVersion": "11.15.0", - "pnpmVersion": "11.2.2", + "version": "24.16.0", + "npmVersion": "11.16.0", + "pnpmVersion": "11.5.0", "nvmVersion": "0.40.4" } }, diff --git a/.github/actions/safe-yarn-install-using-cache/action.yml b/.github/actions/safe-yarn-install-using-cache/action.yml new file mode 100644 index 0000000000..ccfa01f22a --- /dev/null +++ b/.github/actions/safe-yarn-install-using-cache/action.yml @@ -0,0 +1,36 @@ +name: 'Safe yarn install using cache' +description: 'Restore yarn/Cypress cache, install safe-chain, and run yarn install' + +runs: + using: composite + steps: + - uses: actions/cache@v5 + with: + path: | + ~/.cache/yarn + ~/.cache/Cypress + key: ${{ runner.os }}-yarn-cache-${{ hashFiles('**/yarn.lock') }} + + - uses: actions/cache@v5 + id: safe-chain-cache + with: + path: ~/tmp/safe-chain + key: ${{ runner.os }}-safe-chain-1.5.3 + + - name: Download safe-chain script + if: steps.safe-chain-cache.outputs.cache-hit != 'true' + shell: bash + run: | + mkdir -p ~/tmp/safe-chain + curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh -o ~/tmp/safe-chain/install-safe-chain.sh + + - name: Install safe-chain + shell: bash + run: sh ~/tmp/safe-chain/install-safe-chain.sh --ci + + - name: Install + shell: bash + env: + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 + SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" + run: yarn install --frozen-lockfile diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4a9c87afb2..db5feb2f59 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v2 diff --git a/.github/workflows/dhis2-verify-commits.yml b/.github/workflows/dhis2-verify-commits.yml index cbdea9189c..544b6b6720 100644 --- a/.github/workflows/dhis2-verify-commits.yml +++ b/.github/workflows/dhis2-verify-commits.yml @@ -9,26 +9,11 @@ jobs: if: github.event.pull_request.user.login != 'dependabot[bot]' && github.event.pull_request.user.login != 'dhis2-bot' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: 18.x - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - - name: Install safe-chain - if: steps.yarn-cache.outputs.cache-hit != 'true' - run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci - - name: Install - if: steps.yarn-cache.outputs.cache-hit != 'true' - env: - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" - run: yarn install --frozen-lockfile + cache: '' + - uses: ./.github/actions/safe-yarn-install-using-cache - id: commitlint run: echo ::set-output name=config_path::$(node -e "process.stdout.write(require('@dhis2/cli-style').config.commitlint)") - uses: JulienKode/pull-request-name-linter-action@v0.5.0 @@ -39,28 +24,13 @@ jobs: if: github.event.pull_request.user.login != 'dependabot[bot]' && github.event.pull_request.user.login != 'dhis2-bot' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - - uses: actions/setup-node@v3 - with: - node-version: 18.x - - uses: actions/cache@v4 - id: yarn-cache + - uses: actions/setup-node@v6 with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - - name: Install safe-chain - if: steps.yarn-cache.outputs.cache-hit != 'true' - run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci - - name: Install - if: steps.yarn-cache.outputs.cache-hit != 'true' - env: - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" - run: yarn install --frozen-lockfile + cache: '' + - uses: ./.github/actions/safe-yarn-install-using-cache - id: commitlint run: echo ::set-output name=config_path::$(node -e "process.stdout.write(require('@dhis2/cli-style').config.commitlint)") - uses: wagoid/commitlint-github-action@v4 diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index f638c4f9f2..44cea12130 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -42,7 +42,7 @@ jobs: outputs: matrix: ${{ steps.set-matrix.outputs.specs }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 - name: Generate test matrix id: set-matrix run: | @@ -64,7 +64,7 @@ jobs: echo "::set-output name=labels::[ ${labels%,} ]" - if: contains(fromJson(steps.json-labels.outputs.labels), github.event.label.name) - uses: actions/checkout@v2 + uses: actions/checkout@v6 - name: compute-instance-url id: instance-url @@ -91,11 +91,11 @@ jobs: env: SHOULD_RECORD: ${{ contains(github.event.head_commit.message, '[e2e record]') || contains(join(github.event.pull_request.labels.*.name), 'e2e record') }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - name: compute-instance-url id: instance-url @@ -119,24 +119,7 @@ jobs: echo "Computed CI Build ID=${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_CI_BUILD_ID || '' }}" echo "Spec=${{ join(matrix.spec-group.tests, ',') }}" - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - - - name: Install safe-chain - if: steps.yarn-cache.outputs.cache-hit != 'true' - run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci - - - name: Install - if: steps.yarn-cache.outputs.cache-hit != 'true' - env: - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" - run: yarn install --frozen-lockfile + - uses: ./.github/actions/safe-yarn-install-using-cache - name: Cypress run uses: cypress-io/github-action@v6 diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 2623b1c861..07f00f815a 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -9,28 +9,12 @@ jobs: runs-on: ubuntu-latest if: (github.event.label.name == 'preview' || github.event.label.name == 'testing') && !github.event.push.repository.fork && github.actor != 'dependabot[bot]' steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - - - name: Install safe-chain - if: steps.yarn-cache.outputs.cache-hit != 'true' - run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci - - name: Install - if: steps.yarn-cache.outputs.cache-hit != 'true' - env: - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" - run: yarn install --frozen-lockfile + - uses: ./.github/actions/safe-yarn-install-using-cache - name: Build run: yarn build:standalone diff --git a/.github/workflows/verify-app.yml b/.github/workflows/verify-app.yml index 71237e9e9d..0d75f43249 100644 --- a/.github/workflows/verify-app.yml +++ b/.github/workflows/verify-app.yml @@ -20,47 +20,24 @@ jobs: runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - - uses: actions/cache@v4 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} - - - name: Install safe-chain - if: steps.yarn-cache.outputs.cache-hit != 'true' - run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.3/install-safe-chain.sh | sh -s -- --ci - - - name: Install - if: steps.yarn-cache.outputs.cache-hit != 'true' - env: - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 - SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" - run: yarn install --frozen-lockfile + - uses: ./.github/actions/safe-yarn-install-using-cache lint: runs-on: ubuntu-latest needs: install if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - uses: ./.github/actions/safe-yarn-install-using-cache - name: Lint run: yarn linter:check @@ -70,18 +47,12 @@ jobs: if: "!contains(github.event.head_commit.message, '[skip ci]')" needs: install steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - uses: ./.github/actions/safe-yarn-install-using-cache - name: TypeScript run: yarn tsc:check @@ -91,18 +62,12 @@ jobs: needs: install if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - uses: ./.github/actions/safe-yarn-install-using-cache - name: Unit tests run: yarn test @@ -127,7 +92,7 @@ jobs: outputs: matrix: ${{ steps.set-matrix.outputs.specs }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 - name: Generate test matrix id: set-matrix run: | @@ -144,10 +109,10 @@ jobs: env: SHOULD_RECORD: ${{ contains(github.event.head_commit.message, '[e2e record]') || contains(join(github.event.pull_request.labels.*.name), 'e2e record') }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - name: Set Cypress Environment Variables run: | @@ -165,13 +130,7 @@ jobs: echo "Computed CI Build ID=${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_CI_BUILD_ID || '' }}" echo "Spec=${{ join(matrix.spec-group.tests, ',') }}" - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - uses: ./.github/actions/safe-yarn-install-using-cache - name: Cypress run uses: cypress-io/github-action@v6 @@ -204,23 +163,17 @@ jobs: needs: [lint, typescript, unit-tests] if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - uses: ./.github/actions/safe-yarn-install-using-cache - name: Build run: yarn build - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: app-build path: | @@ -233,25 +186,19 @@ jobs: needs: build if: "!github.event.push.repository.fork && !contains(github.event.head_commit.message, '[skip ci]') && github.actor != 'dependabot[bot]'" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 with: token: ${{ env.GH_TOKEN }} - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v6 with: - node-version: 18.x + cache: '' - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v7 with: name: app-build - - uses: actions/cache@v4 - id: yarn-cache - with: - path: | - **/node_modules - ~/.cache/Cypress - key: ${{ runner.os }}-node_modules-cypress-${{ hashFiles('**/yarn.lock') }} + - uses: ./.github/actions/safe-yarn-install-using-cache - uses: dhis2/action-semantic-release@use-yarn-version-prepare with: diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..a45fd52cc5 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24 diff --git a/i18n/en.pot b/i18n/en.pot index 00f2c668d3..0463c7978b 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2026-05-28T10:37:18.094Z\n" -"PO-Revision-Date: 2026-05-28T10:37:18.094Z\n" +"POT-Creation-Date: 2026-06-01T04:06:52.888Z\n" +"PO-Revision-Date: 2026-06-01T04:06:52.888Z\n" msgid "The application could not be loaded." msgstr "The application could not be loaded." From 2e8ceb3af1fdaac27c7021e3e7c822432969eaad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Storl=C3=B8kken=20Melseth?= Date: Mon, 1 Jun 2026 04:35:52 +0000 Subject: [PATCH 4/6] chore: up cypress action version --- .github/workflows/e2e-tests.yml | 2 +- .github/workflows/verify-app.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 44cea12130..4add4afd27 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -122,7 +122,7 @@ jobs: - uses: ./.github/actions/safe-yarn-install-using-cache - name: Cypress run - uses: cypress-io/github-action@v6 + uses: cypress-io/github-action@v7 with: install: false record: ${{ env.SHOULD_RECORD }} diff --git a/.github/workflows/verify-app.yml b/.github/workflows/verify-app.yml index 0d75f43249..f87366baaf 100644 --- a/.github/workflows/verify-app.yml +++ b/.github/workflows/verify-app.yml @@ -133,7 +133,7 @@ jobs: - uses: ./.github/actions/safe-yarn-install-using-cache - name: Cypress run - uses: cypress-io/github-action@v6 + uses: cypress-io/github-action@v7 with: install: false record: ${{ env.SHOULD_RECORD }} From a42ee47c88e651b0502208972d84de5e20761ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Storl=C3=B8kken=20Melseth?= Date: Mon, 1 Jun 2026 06:22:41 +0000 Subject: [PATCH 5/6] chore: testing --- .github/actions/safe-yarn-install-using-cache/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/safe-yarn-install-using-cache/action.yml b/.github/actions/safe-yarn-install-using-cache/action.yml index ccfa01f22a..339678ea8d 100644 --- a/.github/actions/safe-yarn-install-using-cache/action.yml +++ b/.github/actions/safe-yarn-install-using-cache/action.yml @@ -33,4 +33,4 @@ runs: env: SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" - run: yarn install --frozen-lockfile + run: yarn install --frozen-lockfile --safe-chain-logging=verbose From e10328020bc81fbda7e6f7fcf97c1f6164a96d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Storl=C3=B8kken=20Melseth?= Date: Mon, 1 Jun 2026 06:26:36 +0000 Subject: [PATCH 6/6] chore: default logging --- .github/actions/safe-yarn-install-using-cache/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/safe-yarn-install-using-cache/action.yml b/.github/actions/safe-yarn-install-using-cache/action.yml index 339678ea8d..ccfa01f22a 100644 --- a/.github/actions/safe-yarn-install-using-cache/action.yml +++ b/.github/actions/safe-yarn-install-using-cache/action.yml @@ -33,4 +33,4 @@ runs: env: SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: 120 SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@dhis2/*" - run: yarn install --frozen-lockfile --safe-chain-logging=verbose + run: yarn install --frozen-lockfile