Skip to content

Release 3.37.0 - #417

Merged
adrianq merged 49 commits into
masterfrom
development
Aug 26, 2026
Merged

adrianq merged 49 commits into
masterfrom
development

Conversation

@adrianq

@adrianq adrianq commented Aug 26, 2026

Copy link
Copy Markdown
Member

📌 References

  • Issue: Closes #
  • d2-api: Requires #
  • d2-ui-components: Requires #

📝 Implementation

🔥 Notes for the reviewer

📹 Screenshots/Screen capture

📑 Others

idelcano and others added 30 commits June 22, 2026 14:46
Hidden author-set opt-in that lets custom dataSet templates enable multi
org unit selection in the download picker (previously forced single-select).
Add hidden orgUnitSort:"ALPHABETICAL" opt-in for custom dataSet templates.
When set, DownloadTemplateUseCase orders the exported data entries by each
org unit's ancestor-name path (pre-order, siblings alphabetical), matching
the org unit tree. displayName rides the existing getElement fetch, so no
extra API call.
Replace the mirrored useState + set/reset with a value derived from the
selected custom template, removing state that had to be kept in sync.
…tions

- Re-resolve stale transitives within the ranges their parents already
  request: handlebars 4.7.9, @babel/traverse 7.29.8, pbkdf2, minimist,
  sha.js, cipher-base, postcss, semver, json5, picomatch, tar and others.
- Convert the inherited exact-version pins to floors: axios ^1.18.0,
  lodash/lodash-es ^4.18.0, form-data ^4.0.6, minimatch ^3.1.4,
  brace-expansion ^1.1.17, qs ^6.15.3, jszip ^3.8.0. An exact version
  cannot select a patch, so each had stopped doing its job. They cannot
  simply be dropped: @eyeseetea/d2-api requests exact axios@1.6.4,
  lodash@4.17.21 and qs@6.9.7, so removing a constraint resolves downwards.
- Add scoped resolutions react-linkify/linkify-it ^5.0.2 and
  i18next-conv/node-gettext ^3.0.1, where the parent ranges cannot reach
  the fix and the parents are themselves pinned by their consumers.
- Migrate vite ^4.2.0 to ^7.3.6 and vitest ^0.32.2 to ^3.2.7, with
  @vitejs/plugin-react ^5.1.0 and vite-plugin-checker ^0.11.0, pulling
  esbuild to 0.28.1. vite 7 is required because 6.4.3 caps esbuild at
  ^0.25.0. Stopping at vite-plugin-checker 0.11.0 keeps eslint 8.
- Remove babel-core@6.26.3 and postcss-rtl@1.7.3: both unused, and the sole
  paths to babel-traverse@6.26.0 and postcss@6.0.23.
- Remove the path-to-regexp resolution, which matched no descriptor.

Add RESOLUTIONS.md, documenting every resolution with why/fixes/drop-when,
the inherited pins whose rationale was never recorded, and the reason the
archived @dhis2/d2-i18n-* pair is not yet replaced.
- Re-resolve within the ranges parents already request: micromatch 4.0.8,
  browserslist 4.28.7, word-wrap 1.2.5, path-parse 1.0.7, bn.js 4.12.5,
  @sideway/formula 3.0.1, joi 17.13.4, yaml 1.10.3, ajv 6.15.0,
  @tootallnate/once 2.0.1, @babel/helpers and @babel/runtime-corejs3 7.29.7.
- Bump react-router-dom to 6.30.4, the patched release on the 6.x line.
- Open @babel/core and @babel/preset-typescript from exact 7.16.7 to ranges.
  babel-preset-react-app and eslint-config-react-app already request ^7.16.0,
  so this collapses the two babel versions in the tree onto one.

Record in RESOLUTIONS.md the two findings with no remediation available:
elliptic, whose advisory covers every published version, and a withdrawn
eslint advisory that should be dismissed rather than fixed.
The entry cited GHSA-g8qh-9h27-crr2, which does not exist. The advisory is
GHSA-g974-hxvm-x689 — same package, same affected range (<= 3.0.0), same
absence of a recorded patched version, so the reasoning in the entry is
unchanged.
The three remaining react-router advisories had no entry in RESOLUTIONS.md,
so the reasoning lived only in the PR description and would have been lost
once the PR closed.

Records that the 6.x line has no fix — two advisories are patched in 7.18.0
and the third covers 6.30.4, the final 6.x release — that the bump to 6.30.4
still cleared a fourth advisory, and that anyone picking up the migration
should go straight to v7 rather than stopping on 6.x.
Each was tested by removing it, re-installing and comparing the resolved
versions. None of the four changes what is installed in a way that
matters, and all remaining versions are outside every advisory that
affects them.

form-data and jszip were inert. Every parent range already reaches the
patched release - form-data stays at 4.0.6 and jszip at 3.10.1 with or
without the entry. The original reasoning noted that d2-api requests
form-data at ^4.0.0 'which admits affected 4.0.x releases', which is
true but incomplete: ^4.0.0 admits the patched 4.0.6 as well.

minimatch and brace-expansion met the drop-when condition the minimatch
entry itself recorded. The seven parents that request minimatch declare
^3.0.4, which already admits the patched 3.1.5, and brace-expansion only
existed on the 1.x line because minimatch was held at 3.x. Removing both
gives minimatch 10.2.6 alongside 3.1.5, and brace-expansion 5.0.9
alongside 1.1.18 - all four patched.

Removing the minimatch entry also lets glob@13.0.6 have the ^10.2.2 it
declares, instead of being pulled down seven majors.

Records why that downgrade never broke glob@13 - its default entry is a
bundle with minimatch inlined - so the next audit does not re-investigate
it, and notes the compatibility checks behind the linkify-it entry.

Also restates the retirement test as 'does a resolved version move'
rather than 'is the lockfile byte-identical'. The latter proves a
constraint did nothing, but the reverse does not hold.

Verified: yarn install --immutable, tsc --noEmit, lint, 137 tests,
localize, build.
Eight resolutions inherited from the copied February 2026 security commit
were written as exact versions. By their own descriptions several are
security floors, which is the shape that cannot receive a patch and
eventually becomes the finding it was added to prevent - the same decay
that had already happened to axios and qs in this repository.

None of them was inside a live advisory range, checked against the
published advisory database, so this is not a remediation. It removes a
decay path before it opens.

  @babel/runtime  7.26.10 -> ^7.26.10   resolves 7.29.7
  glob-parent     5.1.2   -> ^5.1.2     resolves 5.1.2
  moment          2.29.4  -> ^2.29.4    resolves 2.30.1
  nanoid          3.3.8   -> ^3.3.8     resolves 3.3.17
  node-fetch      2.6.7   -> ^2.6.7     resolves 2.7.0
  diff            5.2.2   -> ^5.2.2     resolves 5.2.2
  debug           4.3.4   -> ^4.3.4     resolves 4.4.3
  ua-parser-js    0.7.24  -> ^0.7.24    resolves 0.7.41

A caret keeps every consumer on the major the exact version already
forced it onto, so no package changes line. All eight resulting versions
are outside every advisory affecting them.

i18next is deliberately left exact: it sits far below the current release
line and a resolution on it can break application startup, so it changes
only with an app-startup check behind it.

The direct moment dependency was reopened to the same range; it still
said 2.29.4 while the resolution allowed more, which is the same
contradiction axios and lodash had.

Also records that nanoid was holding postcss below the ^3.3.16 it
declares, and node-fetch below the ^2.7.0 one consumer declares - a
constraint holding a consumer beneath its own parent's range is worth
treating as a signal in itself.

Verified: install --immutable, tsc --noEmit, lint, 137 tests, localize
with no content change, full build, and moment 2.30.1 formatting with a
Spanish locale.
.yarnrc.yml declared only nodeLinker, so three of the four supply-chain
settings fell back to yarn's defaults, which are looser than what the
other repositories in this family run:

                      before (effective)  after
  npmMinimalAgeGate   0                   7d
  enableScripts       true                false
  enableHardenedMode  null                true
  checksumBehavior    throw               throw (already matched)

None of these was a decision - they were simply never declared - so this
repository was the most permissive of the three while carrying the same
kind of dependency risk.

Alignment costs nothing here: the lockfile comes back byte-identical, and
install, typecheck, lint, tests, localize and the full build all pass
unchanged.

enableScripts: false is the one worth knowing about. Yarn now reports
YN0004 for esbuild and three core-js variants. Neither breaks - esbuild
ships its binary as a platform-specific optional package rather than
fetching it in a postinstall, verified by running a transform through it,
and core-js's script only prints a funding message. RESOLUTIONS.md now
carries that note, along with the warning that the age gate is what makes
a reachable fix look unreachable.

Verified: install --immutable, tsc --noEmit, lint, 137 tests, localize,
full build, and an esbuild transform executed directly.
Two corrections found while aligning this file with the same work in another
repository.

`debug` moves from `^4.3.4` to `^4.4.3`. GHSA-4x49-vf9v-38px reports
`debug@4.4.2` as carrying malware after an npm account takeover, so `^4.4.3`
is the meaningful lower bound. The old floor resolved to 4.4.3 in practice,
because yarn picks the newest, but it would have admitted 4.4.2 - a floor is
a guarantee and that one did not give it. No resolved version changes.

`glob-parent` is retired. Its own note already flagged it as the most likely
candidate, and the advisory ranges confirm it. Removing it lets three lines
coexist - 3.1.0 through `glob-stream@6.1.0`, 5.1.2 through eslint and
chokidar, 6.0.2 through the `^6.0.1` consumer - and none of them is in range:
GHSA-ww39-953v-wcq6 affects `>= 4.0.0, < 5.1.2`, which 3.1.0 sits below, and
GHSA-cj88-88mr-972w affects `= 6.0.0` only. The entry was not keeping a
vulnerable version out; it was holding two consumers off the majors they
declare. `is-glob@3.1.0` and `path-dirname@1.0.2` return with it and have no
advisory at any version.

Verified with yarn install --immutable, lint, 137 tests, yarn localize - the
i18next-scanner chain is what reaches the 3.1.0 copy - and the full build.
This file, and the equivalent in the other repositories that carry one, now
state the same rule set. Four of the rules were learned the hard way during
this round of work and existed in only one file each.

- The version in a versioned-parent path is the descriptor, not the resolved
  version. An entry keyed on a `version:` line was inert from the day it was
  written.
- A versioned-parent path cannot select a version outside the range the parent
  declares; a parent-name path can. This is why two sibling pins on the same
  matched parent behave differently, which had been recorded as an anomaly.
- An older version returning when a constraint is removed is not by itself a
  reason to keep it. Check the advisory range first: one entry was keeping out
  a version that no advisory covered.
- Validate the control before trusting a zero from the advisories API. It
  returns nothing both for a clean version and for one that was never
  published, and those look identical.

No manifest change, and no resolved version moves.
The new rules cited another repository as their source. A reader of this file
cannot open that reference, which leaves an assertion with no way to check it,
so each is restated as the rule itself with a verifiable example.
anagperal and others added 19 commits August 13, 2026 12:17
An entry that names the advisories it knows about, without saying how many
exist, reads the same whether it is complete or not. Written during a pass
filtered to critical and high, it can describe a component as healthier than
the scanner does, and the next audit has no way to tell.

Each accepted finding now states how many advisories are live against the
installed version, and how many others exist against the package and are
already patched below it. Withdrawn records are counted separately, because
scanner output may still show them: uuid@3.4.0 matches two, one of which is a
withdrawn duplicate of the other, and eslint@8.57.1 matches only a withdrawn
one and so has no live advisory at all.

Counts taken from the advisories API on 2026-08-13, not from the scan.
…e-org-units

[Feature] multi org unit selection and alphabetical row order for custom dataSets
[feature]: Make import completion status configurable, including per record
GHSA-2v37-7h3g-55p8 (high) affects nanoid < 3.3.18 and reaches the tree
through postcss, which declares ^3.3.8. The advisory was published on
2026-08-07, after the branch's main commits, so this is decay rather than
a defect: the resolution already read ^3.3.8 and 3.3.18 is past the 7d
npmMinimalAgeGate, so `yarn up -R nanoid` reached it with no manifest
change.

`yarn npm audit -R --severity high` is clean again.
None of these is read by anything in the tree:

-   `BROWSER`, `SKIP_PREFLIGHT_CHECK`, `REACT_APP_DHIS2_BASE_URL`,
    `REACT_APP_DEBUG` and `GENERATE_SOURCEMAP` are Create React App
    variables. Vite exposes only `VITE_*` to the app and takes the
    sourcemap setting from `vite.config.ts`, so they have had no effect
    since the migration. `.env.development` and `.env.production` held
    nothing else and are removed.
-   `PORT` was still read as a fallback in `vite.config.ts`, but `.env`
    also sets `VITE_PORT` to the same 8081. Keeping two names for one
    setting, one of them a CRA carry-over, is worse than keeping the
    documented one.
-   `cypress.json` is an empty object, there is no `cypress/` directory
    and Cypress is not a dependency, so the three `CYPRESS_*` variables
    have nothing to configure. `wait-on`, the devDependency that paired
    with it, is referenced by no script and goes with them.

Verified: `yarn lint`, `tsc --noEmit` and `yarn test` (137 tests) pass,
`vite build` succeeds and the dev server still comes up on 8081.
…bilities

[SECURITY] resolve dependency vulnerabilities
…9cc53c7

add org. units imported to history summary
@adrianq
adrianq merged commit 5555d79 into master Aug 26, 2026
16 of 17 checks passed
@bundlemon

bundlemon Bot commented Aug 26, 2026 •

Copy link
Copy Markdown

BundleMon

No change in files bundle size

Groups updated (1)
Status Path Size Limits
✅ Build Folder
./**/*
1.73MB (-14.63KB -0.82%) +20%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants