openstack-uicore-foundation 5.0.53-beta.2 → 5.0.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/openstack-uicore-foundation-components.md +67 -0
- package/.claude/rules/openstack-uicore-foundation-project.md +69 -0
- package/.claude/rules/openstack-uicore-foundation-security.md +39 -0
- package/.claude/settings.local.json +7 -0
- package/.codegraph/.gitignore +5 -0
- package/docs/plans/2026-04-09-showconfirmdialog-react16-compat.md +83 -0
- package/docs/plans/2026-04-22-dropzone-pooling-ux.md +129 -0
- package/docs/plans/2026-04-23-uploadv3-duplicate-file-max-reached.md +109 -0
- package/docs/plans/2026-04-23-uploadv3-premature-complete-on-202.md +99 -0
- package/docs/plans/2026-07-06-file-size-field-unit-prop.md +20 -0
- package/docs/plans/2026-07-30-node-22-migration.md +139 -0
- package/docs/plans/clickup-barrel-mui-dragalong.md +43 -0
- package/docs/plans/clickup-order-ledger-extraction.md +44 -0
- package/docs/plans/clickup-uploadv3-progress-bar-large-files.md +42 -0
- package/package.json +1 -1
- package/.claude/RESUME.md +0 -23
- package/package-lock.json +0 -22291
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Node 22 Migration Implementation Plan
|
|
2
|
+
|
|
3
|
+
Created: 2026-07-30
|
|
4
|
+
Author: smarcet@gmail.com
|
|
5
|
+
Agent: Claude Code
|
|
6
|
+
Status: VERIFIED
|
|
7
|
+
Approved: Yes
|
|
8
|
+
Iterations: 0
|
|
9
|
+
Worktree: No
|
|
10
|
+
Type: Feature
|
|
11
|
+
|
|
12
|
+
## Summary
|
|
13
|
+
|
|
14
|
+
**Goal:** openstack-uicore-foundation builds, tests, and runs cleanly on Node 22 LTS (22.22.1), extrapolating the Node 18→22 migration from `fntechgit/summit-admin` PR #844 / ClickUp ticket 86b8zyqnf.
|
|
15
|
+
|
|
16
|
+
## Out of Scope
|
|
17
|
+
|
|
18
|
+
- **Literal SCSS/sass-loader removal.** The ticket tells summit-admin to delete `node-sass`, `sass-loader`, and all SCSS webpack/jest rules because their `.scss` was dead code. This lib's `.scss` is live (6 files: `circle-button`, `progressive-img`, `extra-questions`, `mui/NavBar`, `mui/AuthButton`, `schedule-print`), so instead of deleting SCSS support, `node-sass` is swapped for dart-sass (`sass`) — see Approach.
|
|
19
|
+
- **`fs`, `react-hot-loader` removal, `superagent`/`idtoken-verifier` version bumps.** None of these apply: this repo's `package.json` never had `fs` or `react-hot-loader`, and `superagent` (8.0.9) / `idtoken-verifier` (^2.2.2) are already the target versions the ticket asks summit-admin to bump *to* (this lib is the upstream source of those peer-dep versions).
|
|
20
|
+
- **webpack-cli v4→v5 bump, `webpack.dev.js` HTTPS devServer config, `.prettierrc` key rename.** This lib has no `serve` script (only `build-dev`/`build`, which invoke `webpack` directly, not `webpack serve`), so `webpack-cli`/devServer config is inert here — confirmed webpack-cli 4.9.2 already builds successfully on Node 22. No `.prettierrc` exists in this repo (prettier isn't installed).
|
|
21
|
+
- **ESLint upgrade.** Not applicable — this repo has no `eslint` dependency at all and no `lint` script (unlike summit-admin, which has both and defers its 8→9 migration to a separate ticket).
|
|
22
|
+
- **React 16→18, Redux 3→4 upgrades.** Explicitly out of scope in the source ticket too (separate tickets).
|
|
23
|
+
|
|
24
|
+
## Approach
|
|
25
|
+
|
|
26
|
+
**Chosen:** Direct config/dependency edits to `.nvmrc`, the two `.github/workflows/*.yml` files, `package.json`, and `webpack.common.js` — swapping `node-sass` for dart-sass rather than deleting SCSS support.
|
|
27
|
+
**Why:** Matches the upstream Node 22 migration's intent (clean dependency tree, no build tooling incompatible with Node 22) without regressing this library's actively-used SCSS components. Confirmed by reproducing the real blocker: `node-sass` 7.0.1 ships no Node 22 binary, so `sass-loader` silently returns `undefined` CSS and `webpack --config webpack.dev.js` fails with a PostCSS "received undefined instead of CSS string" error on `schedule-print/styles.module.scss`. Installing dart-sass (`sass@^1.77.0`) fixes this: `sass-loader` auto-prefers `sass` over `node-sass` with no config changes, and dart-sass's legacy `renderSync` API (what `sass-loader@12` uses) was verified against `circle-button/index.module.scss` directly — it renders correctly with no deprecation warnings at this version.
|
|
28
|
+
|
|
29
|
+
## Context for Implementer
|
|
30
|
+
|
|
31
|
+
Two Babel configs exist, same as noted in the source ticket: `babel.config.json` (used by Jest/babel-jest — already uses `@babel/plugin-transform-runtime`, unaffected) and inline `options.plugins` inside the `babel-loader` rule in `webpack.common.js:217-220` (used only by webpack). The `proposal`→`transform` plugin renames apply to `package.json` **and** `webpack.common.js` — missing either leaves a mismatched package name that webpack/babel can't resolve.
|
|
32
|
+
|
|
33
|
+
## Assumptions
|
|
34
|
+
|
|
35
|
+
- `sass@^1.77.0` (dart-sass) renders this repo's existing `.scss` files without syntax changes — verified directly against `circle-button/index.module.scss` via `sass.renderSync()`, the same legacy API `sass-loader@12.6.0` invokes by default. Task 2 depends on this holding for the other 5 `.scss` files too (all are equally simple: plain selectors, nesting, `&` — no `@import`, no Sass-specific at-rules that differ between node-sass and dart-sass). **Confirmed correct in Task 4**: `yarn build-dev` compiled all 6 `.scss` files to correct CSS (verified generated class names/rules in `lib/css/components/circle-button.css`, `mui/nav-bar.css`, etc.). One discovered difference from the isolated pre-approval test: `yarn.lock` resolved `sass` to `1.102.0` (latest satisfying `^1.77.0`, not the `1.77.8` tested directly), and going through `sass-loader`'s actual invocation (vs. calling `sass.renderSync()` raw) surfaced a `Deprecation The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0` warning during every build. Cosmetic (build exit code and CSS output were both correct), but resolved as a same-day follow-up: bumped `sass-loader` `^12.6.0` → `^14.2.1` (requires Node ≥18.12, satisfied) and added `api: 'modern'` to both SCSS loader rules in `webpack.common.js` (`.module.scss` and `.scss`). Re-verified: `yarn build-dev`/`yarn build` both compile with zero sass deprecation warnings, generated CSS is byte-identical in content to the legacy-API build (same class rules/counts across all 6 `.scss` files), and the full suite still passes 104/104 suites, 876/876 tests.
|
|
36
|
+
- Bumping `jest`/`jest-environment-jsdom` 28→29.7.0 together is compatible with `babel-jest`, `identity-obj-proxy`, `jest-transform-stub`, and `redux-mock-store` as currently configured — no snapshot tests exist in this repo (`find src -name '*.snap'` = 0 results), which removes the most common jest-major-bump breakage source. Task 3 depends on this; the full 876-test suite re-run in Task 4 is the check.
|
|
37
|
+
|
|
38
|
+
## Progress Tracking
|
|
39
|
+
|
|
40
|
+
- [x] Task 1: Bump Node version pins to 22.22.1 (.nvmrc, CI workflows)
|
|
41
|
+
- [x] Task 2: Migrate dependencies for Node 22 (babel plugin renames, node-sass → dart-sass, remove babel-cli)
|
|
42
|
+
- [x] Task 3: Bump jest + jest-environment-jsdom to 29.7.0
|
|
43
|
+
- [x] Task 4: Reinstall on Node 22 and verify full build/test pipeline (punycode warning not eliminated — documented, structural jest-29 limitation)
|
|
44
|
+
|
|
45
|
+
## Implementation Tasks
|
|
46
|
+
|
|
47
|
+
### Task 1: Bump Node version pins to 22.22.1
|
|
48
|
+
|
|
49
|
+
**Objective:** Pin the toolchain to Node 22 LTS (22.22.1, the version named in ClickUp ticket 86b8zyqnf) across the local dev environment and CI, mirroring the `node-version: 18` → `22` change in PR #844's three GitHub Actions workflows (this repo only has two of those three workflows).
|
|
50
|
+
|
|
51
|
+
**Files:**
|
|
52
|
+
|
|
53
|
+
- Modify: `.nvmrc`
|
|
54
|
+
- Modify: `.github/workflows/build_test.yml`
|
|
55
|
+
- Modify: `.github/workflows/jest.yml`
|
|
56
|
+
|
|
57
|
+
**Key Decisions / Notes:**
|
|
58
|
+
|
|
59
|
+
- `.nvmrc` currently reads `18.15.0` (`.nvmrc:1`) → `22.22.1`, matching the exact LTS patch the ticket pins for summit-admin.
|
|
60
|
+
- Both workflow files set `node-version: 18` under the `actions/setup-node@v3` step (`build_test.yml:13`, `jest.yml:13`) → `node-version: 22`, matching PR #844's style (major version only, not a full patch pin, for the `setup-node` action).
|
|
61
|
+
- `Trivial:` three one-line version-string edits, no logic change; covered by Task 4's full pipeline re-run (`.nvmrc`/workflow correctness can't be unit-tested directly — CI executing on Node 22 is the verification).
|
|
62
|
+
|
|
63
|
+
**Definition of Done:**
|
|
64
|
+
|
|
65
|
+
- [ ] `.nvmrc` contains `22.22.1`
|
|
66
|
+
- [ ] Both `.github/workflows/*.yml` files specify `node-version: 22`
|
|
67
|
+
- [ ] Verify: `grep -c "node-version: 22" .github/workflows/build_test.yml .github/workflows/jest.yml` → each file reports 1
|
|
68
|
+
|
|
69
|
+
### Task 2: Migrate dependencies for Node 22 (babel renames, node-sass → dart-sass, remove babel-cli)
|
|
70
|
+
|
|
71
|
+
**Objective:** Replace the Node-22-incompatible `node-sass` with dart-sass, rename the deprecated `@babel/plugin-proposal-*` packages to their `@babel/plugin-transform-*` equivalents in both places they're declared, and drop the unused `babel-cli` devDependency — the three dependency-level blockers/deprecations PR #844 addresses that actually apply to this repo.
|
|
72
|
+
|
|
73
|
+
**Files:**
|
|
74
|
+
|
|
75
|
+
- Modify: `package.json`
|
|
76
|
+
- Modify: `webpack.common.js`
|
|
77
|
+
|
|
78
|
+
**Key Decisions / Notes:**
|
|
79
|
+
|
|
80
|
+
- `package.json:78` — remove `"node-sass": "^7.0.1"`; add `"sass": "^1.77.0"` to `devDependencies` (alphabetically, near `redux-thunk`/`regenerator-runtime`). `sass-loader` (`node_modules/sass-loader/dist/utils.js:27-47`) auto-detects and prefers `sass` over `node-sass` when both/either are present — no `sass-loader` option changes needed.
|
|
81
|
+
- `package.json:18-20` — rename `@babel/plugin-proposal-class-properties` → `@babel/plugin-transform-class-properties`, `@babel/plugin-proposal-object-rest-spread` → `@babel/plugin-transform-object-rest-spread`, `@babel/plugin-proposal-optional-chaining` → `@babel/plugin-transform-optional-chaining` (same `^7.16.7`/`^7.17.3` version ranges — these are drop-in renames, confirmed via `npm view <proposal-pkg> deprecated` pointing at the `transform-*` replacement). This repo doesn't declare `@babel/plugin-proposal-nullish-coalescing-operator` (summit-admin's 4th renamed plugin), so there's nothing to rename for that one.
|
|
82
|
+
- `webpack.common.js:218-220` — same three renames inside the `babel-loader` rule's `options.plugins` array (mirrors `package.json`; see Context for Implementer above).
|
|
83
|
+
- `package.json:43` — remove `"babel-cli": "^6.26.0"` from `devDependencies`. Confirmed unused: no `babel-cli`/`babel-node` reference anywhere outside this one line (`grep -rn "babel-cli\|babel-node" --exclude-dir=node_modules --exclude-dir=lib .`).
|
|
84
|
+
- Do NOT touch `webpack.common.js:118-123` (the `.module.scss`/`.scss` loader rules) or the `package.json` `jest.moduleNameMapper`/`jest.transform` scss entries (`package.json:180`, `:190`) — see Out of Scope.
|
|
85
|
+
|
|
86
|
+
**Definition of Done:**
|
|
87
|
+
|
|
88
|
+
- [ ] `package.json` has no `node-sass` or `babel-cli` entries; has `"sass": "^1.77.0"` in devDependencies
|
|
89
|
+
- [ ] No `@babel/plugin-proposal-*` package name appears anywhere in `package.json` or `webpack.common.js`
|
|
90
|
+
- [ ] Verify: `grep -rn "plugin-proposal\|node-sass\|babel-cli" package.json webpack.common.js` returns no matches
|
|
91
|
+
|
|
92
|
+
### Task 3: Bump jest + jest-environment-jsdom to 29.7.0
|
|
93
|
+
|
|
94
|
+
**Objective:** Upgrade `jest` and `jest-environment-jsdom` together from `^28.1.0` to `^29.7.0` so their internal API versions stay paired, eliminating the `punycode` module deprecation warning that Node 22 emits when running the test suite under jest 28's older jsdom (^19.0.0 → ^20.0.0).
|
|
95
|
+
|
|
96
|
+
**Files:**
|
|
97
|
+
|
|
98
|
+
- Modify: `package.json`
|
|
99
|
+
|
|
100
|
+
**Key Decisions / Notes:**
|
|
101
|
+
|
|
102
|
+
- `package.json:63-64` — `"jest": "^28.1.0"` → `"^29.7.0"`, `"jest-environment-jsdom": "^28.1.0"` → `"^29.7.0"`. Bumping only `jest-environment-jsdom` (the ticket's literal instruction, written for summit-admin where jest core was already 29) would pair a jest-28 core with a jest-29 environment package — an unsupported combination since `jest-environment-jsdom` peer-requires matching `@jest/environment`/`@jest/types` major versions.
|
|
103
|
+
- No snapshot tests exist in this repo (verified: `find src -name '*.snap'` → 0 results), which is the most common jest-major-bump breakage source — reduces migration risk.
|
|
104
|
+
- `package.json:70-71` also declares standalone `jsdom": "^19.0.0"` and `jsdom-global": "^3.0.2"` devDependencies, separate from the jsdom that `jest-environment-jsdom` pulls in transitively. Confirmed unused: no `require('jsdom')`/`require('jsdom-global')` anywhere in `src` (only `@jest-environment jsdom` docblocks, which reference jest's environment config, not these packages directly) — leave both untouched; they're pre-existing dead deps outside this migration's lineage, not a version-mismatch risk.
|
|
105
|
+
- **Before bumping**, capture a baseline for the known-flaky `src/components/mui/__tests__/mui-sponsor-input.test.js` "debounces API calls" fake-timer test on jest 28: run it isolated 3x with `--runInBand` and note the failure mode when it flakes (expected: `toHaveBeenCalledWith("Spo", ...)` receives `"Sp"` — a keystroke-timing race, not a timer-count or assertion-shape error). Jest 29 changed its fake-timers internals (`@sinonjs/fake-timers`), so a post-bump flake must be compared against this baseline failure mode, not assumed to be "the same pre-existing flake" by default. **Result:** 3/3 isolated `--runInBand` runs passed cleanly on jest 28 — confirms the flake is worker-parallelism contention, not deterministic.
|
|
106
|
+
- `Trivial:` two version-string bumps in `devDependencies`; the behavioral verification is Task 4's full suite re-run, not a new unit test.
|
|
107
|
+
- **Found during changes-review (verification phase):** `babel-jest` (`package.json:43`) was left at `^28.1.0` while `jest`/`jest-environment-jsdom` bumped to `^29.7.0` — a version skew flagged because `jest@^29.7.0` needs `babel-jest@^29.7.0` internally, and `yarn.lock` was resolving both `babel-jest@28.1.0` (our stale direct pin) and `babel-jest@29.7.0` (jest's transitive need) simultaneously. Tests passed either way (876/876), but bumped `babel-jest` to `^29.7.0` for consistency with the rest of the jest-family bump and to remove the duplicate install.
|
|
108
|
+
- **Objective partially not achievable within this task's scope, discovered during Task 4 verification:** the punycode warning is NOT eliminated by this bump. Root cause traced with `node --trace-deprecation`: the warning originates from `tr46@3.0.0` (`node_modules/tr46/index.js`, `require('punycode')`), pulled in by `whatwg-url@^11.0.0`, which is what `jsdom@^20.0.0` depends on. `jest-environment-jsdom@29.7.0` — the latest 29.x release, confirmed via `npm view jest-environment-jsdom versions` — permanently pins `jsdom: ^20.0.0` (verified via `npm view jest-environment-jsdom@29.7.0 dependencies.jsdom`); that pin never changes within the 29.x line. `tr46` only stops requiring Node's deprecated built-in `punycode` module (switching to the npm `punycode` package instead) starting at `tr46@5` / `whatwg-url@14`, which first ships with `jsdom@26.1.0` — pulled in only by `jest-environment-jsdom@30.x`, which requires jest 30 core. **This means the punycode warning cannot be eliminated while staying on jest 29** — only a jest 30 upgrade (paired jest + jest-environment-jsdom + jsdom major bump, materially larger and riskier than what this plan's approach question covered) would fix it. Not implemented here: it's a bigger, unreviewed scope expansion beyond the approved "bump jest+jest-environment-jsdom to 29.7.0 together" decision. Flagged as a follow-up for a separate jest 30 migration plan.
|
|
109
|
+
|
|
110
|
+
**Definition of Done:**
|
|
111
|
+
|
|
112
|
+
- [ ] `package.json` declares `jest` and `jest-environment-jsdom` both at `^29.7.0`
|
|
113
|
+
- [ ] Isolated baseline run of `mui-sponsor-input.test.js` on jest 28 recorded (pass, or flake with the `"Sp"` vs `"Spo"` failure mode) before the bump
|
|
114
|
+
- [ ] Verify: `grep -E '"jest(-environment-jsdom)?": "\^29\.7\.0"' package.json` matches both lines
|
|
115
|
+
|
|
116
|
+
### Task 4: Reinstall on Node 22 and verify full build/test pipeline
|
|
117
|
+
|
|
118
|
+
**Objective:** Reinstall dependencies from scratch under Node 22.22.1 (regenerating `yarn.lock`) and confirm the full build and test pipeline is clean — no `node-sass`/PostCSS build errors, and the complete test suite passes — closing out the migration end to end, mirroring PR #844's final "verify full pipeline on Node 22" step. (The `punycode` warning is NOT eliminated — see Task 3's Key Decisions for the traced root cause and why it's out of this plan's scope.)
|
|
119
|
+
|
|
120
|
+
**Files:**
|
|
121
|
+
|
|
122
|
+
- Modify: `yarn.lock` (regenerated by `yarn install`, not hand-edited)
|
|
123
|
+
|
|
124
|
+
**Key Decisions / Notes:**
|
|
125
|
+
|
|
126
|
+
- Use Node 22.22.1 for this verification (matches the `.nvmrc` pin from Task 1): `export PATH="$HOME/.nvm/versions/node/v22.22.1/bin:$PATH"` (already available locally via nvm in this environment).
|
|
127
|
+
- `rm -rf node_modules && yarn install` — clean reinstall so `yarn.lock` reflects the Task 2/3 dependency changes (added `sass`, removed `node-sass`/`babel-cli`, bumped babel/jest packages) rather than a stale partial resolution.
|
|
128
|
+
- This repo has no `lint` or `serve` script (unlike summit-admin), so the equivalent verification surface is `build-dev`, `build`, and `test` only.
|
|
129
|
+
- A pre-existing flaky test (`src/components/mui/__tests__/mui-sponsor-input.test.js`, the `debounces API calls` fake-timer test) intermittently fails under jest's default parallel workers on **both** Node 18 and Node 22 — reproduced independently of this migration. Not caused by or fixed as part of this plan; if it flakes during verification, re-run with `--runInBand` to confirm it's the pre-existing flake and not a real regression.
|
|
130
|
+
- The "876/876 passing" figure in the DoD below is the pre-migration baseline captured during planning: `yarn jest --runInBand` on both Node 18.15.0 and Node 22.22.1 (pre-Task-2/3 dependency state) reported "Test Suites: 104 passed, 104 total / Tests: 876 passed, 876 total". Post-migration, compare against this baseline rather than treating 876 as a hardcoded target — a suite/test count drift (not just a pass/fail count) would indicate a collection-level regression (e.g. a test file failing to load under jest 29) that a bare pass-count comparison could mask.
|
|
131
|
+
- **Deviation found and fixed during this task's verification:** the first post-migration full-suite run failed to *collect* `src/utils/__tests__/actions.test.js` — "Cannot find module 'request'" — a suite/test-count drift exactly matching the scenario the note above warns about. Root cause: `node-sass@^7.0.1` (removed in Task 2) transitively depended on the npm package `request@^2.88.0` (used by its binary-downloader install script); nothing in `src` or this test file ever imports that package (confirmed: `grep` for `require('request')`/`from 'request'` across `src` returns nothing). The test file's `jest.mock('request')` (`actions.test.js:10`, now removed) was pre-existing dead code that only avoided "Cannot find module" by accident, because `request` happened to be resolvable via node-sass's transitive tree — it was never functionally connected to the test (the test's real HTTP client is `superagent/lib/client`, imported under the unrelated local name `request`). Removed the stale `jest.mock('request')` line at the root cause; not a jest 28→29 behavior change.
|
|
132
|
+
|
|
133
|
+
**Definition of Done:**
|
|
134
|
+
|
|
135
|
+
- [x] `yarn install` completes with exit 0 on Node 22.22.1 (no `node-sass` build/postinstall errors)
|
|
136
|
+
- [x] `yarn build-dev` and `yarn build` both complete with exit 0 and no PostCSS "received undefined instead of CSS string" errors
|
|
137
|
+
- [x] `yarn test` reports 876/876 passing (0 failures) — matches the pre-migration baseline exactly (no suite/test count drift)
|
|
138
|
+
- [~] `punycode` deprecation warning: NOT eliminated (root cause traced and documented in Task 3 — structurally impossible on jest 29; needs a separate jest 30 migration). Original DoD wording ("no punycode warning") is not met; superseded by the Task 3 note above.
|
|
139
|
+
- [x] Verify (run): `node -v` (22.22.1) `&& rm -rf node_modules && yarn install && yarn build-dev && yarn build && yarn test --runInBand 2>&1 | tee /tmp/node22-verify.log` → `yarn install` exit 0, both builds exit 0 with no PostCSS "undefined" error, `104 passed, 104 total` suites / `876 passed, 876 total` tests. One regression found and fixed mid-verification: `src/utils/__tests__/actions.test.js` failed to load ("Cannot find module 'request'") because `node-sass` (removed in Task 2) was the transitive source of the `request` npm package that the test's stale, unused `jest.mock('request')` call depended on existing — removed the dead mock line at the root cause (see Task 4 Key Decisions above); suite is green after the fix.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
GOAL
|
|
2
|
+
|
|
3
|
+
Current state: The components barrel (src/components/index.js) exports UploadInputV3 (which imports @mui/material and @mui/icons-material) uncommented, along with 70 additional Mui* components. Any consumer importing from openstack-uicore-foundation/lib/components (the barrel) is forced to resolve @mui/material, @mui/icons-material, @mui/x-date-pickers, spark-md5, dropzone and react-dropzone as installed peerDependencies, even if it uses no MUI component at all. This broke track-chairs build when bumping from 4.2.24 to 4.2.34 (UploadInputV3 was added in 4.2.25), and the same pattern is present on main (v5.x), made worse because the barrel now has 70 uncommented Mui exports (0 in the version right before 4.2.25).
|
|
4
|
+
|
|
5
|
+
Target state: Consumers that don't use MUI (like track-chairs) can update the library without being forced to install the full MUI + spark-md5 + dropzone stack, following the convention already documented in this repo (No barrel imports from lib/) and the pattern already applied to TextEditorV3, CompanyInputV2, MuiStripePayment, etc. (commented out of the barrel but with a standalone webpack entry).
|
|
6
|
+
|
|
7
|
+
TASKS
|
|
8
|
+
|
|
9
|
+
- Audit which of summit-admin's 584 library imports use the barrel (openstack-uicore-foundation/lib/components) vs individual paths, and confirm the 13 barrel imports found don't depend on UploadInputV3/Mui* staying exposed there (summit-admin already uses MUI anyway, low risk for that consumer)
|
|
10
|
+
- Comment out the UploadInputV3 export from src/components/index.js, following the exact same pattern already used for TextEditorV3 (move it under the "// these include 3rd party deps" block); keep its standalone webpack entry (webpack.common.js) untouched so direct imports keep working
|
|
11
|
+
- Fix the 2 summit-admin files that import UploadInputV3 from the barrel before/alongside the release: src/components/upload-dialog/index.js line 26, and src/pages/companies/components/company-dialog.js line 36 (used at lines 481 and 502) — switch both to import from openstack-uicore-foundation/lib/components/inputs/upload-input-v3 directly
|
|
12
|
+
- Update .claude/rules/openstack-uicore-foundation-project.md and the README if the recommended import convention changes
|
|
13
|
+
- Communicate the correct import path to consumers (track-chairs, summit-admin, etc.) to avoid the MUI/spark-md5/dropzone drag-along
|
|
14
|
+
|
|
15
|
+
ACCEPTANCE CRITERIA
|
|
16
|
+
|
|
17
|
+
- A consumer that only imports non-MUI components from openstack-uicore-foundation/lib/components/(individual path) can run yarn install and build without having @mui/material, @mui/icons-material, @mui/x-date-pickers, spark-md5, dropzone or react-dropzone installed
|
|
18
|
+
- The library's webpack build still generates individual entries for each component, including upload-input-v3, without breaking consumers that import it directly (summit-admin)
|
|
19
|
+
- The import convention is documented consistently across README, CLAUDE.md and the actual code
|
|
20
|
+
- No regression in existing tests (jest) or in the library build (yarn build)
|
|
21
|
+
|
|
22
|
+
DEVELOPMENT NOTES
|
|
23
|
+
|
|
24
|
+
Key files:
|
|
25
|
+
src/components/index.js, the main barrel, contains the 70 uncommented Mui* exports and the UploadInputV3 export on line 8
|
|
26
|
+
webpack.common.js, multi-entry build, check the upload-input-v3 and editor-input-v3 entries as reference for the pattern already in use
|
|
27
|
+
src/utils/crypto.js, imports spark-md5 unconditionally, used by dropzone/index.js and by security/methods.js via getSHA256/getRandomBytes even though methods.js never calls getMD5
|
|
28
|
+
package.json, @mui/material, @mui/icons-material, @mui/x-date-pickers, spark-md5, dropzone and react-dropzone are in peerDependencies, not dependencies, consistent with the project's peer deps model
|
|
29
|
+
|
|
30
|
+
Gotchas:
|
|
31
|
+
spark-md5 is not new to UploadInputV3, it was added in v4.2.17 (commit f4474fa) via dropzone/index.js for V1/V2. The real regression in 4.2.25 was that UploadInputV3 was the first component to actually reference @mui/material from the barrel (previously declared as a peer dep but not imported by anything reachable from there) and to add @mui/icons-material as a new peer dep
|
|
32
|
+
On v5.x main the barrel already has 70 uncommented Mui* exports vs 0 before 4.2.25 (all pre-existing, out of scope here), so commenting out UploadInputV3 removes the spark-md5/icons-material-specific drag-along this ticket targets, but a fully MUI-free consumer importing anything else from the barrel still needs MUI because of those 70 exports — tracked separately if it becomes a problem
|
|
33
|
+
summit-admin (5.0.40) already uses MUI extensively, out of 584 imports of the library only 13 use the full barrel (includes UploadInputV3 and MuiFormikUpload), the rest already follow the documented individual-path convention
|
|
34
|
+
track-chairs is the consumer that broke on the 4.2.34 bump, its code was not reviewed in this session, the information about its import pattern comes from the user's initial report
|
|
35
|
+
|
|
36
|
+
Risks:
|
|
37
|
+
Risk: removing UploadInputV3 from the barrel is a breaking change for any consumer relying on that barrel import. Confirmed concretely: summit-admin imports UploadInputV3 from the barrel in src/components/upload-dialog/index.js (line 26) and src/pages/companies/components/company-dialog.js (line 36, used at lines 481 and 502) — both break the moment this ships
|
|
38
|
+
Mitigation: keep the standalone webpack entry, which already exists, and document the alternative import path before removing it from the barrel, communicating the change in release notes. Land the summit-admin import fix in the same window as the openstack-uicore-foundation release (or before it, since importing from the individual path already works today on 5.0.40) to avoid a broken window
|
|
39
|
+
|
|
40
|
+
Out of scope:
|
|
41
|
+
track-chairs code is not investigated in this session, it is outside this repo
|
|
42
|
+
The MUI v9 migration (branch feature/5.x-react-17-x-upgrade, tag v6.0.0-beta.1) is not addressed, it is a separate effort
|
|
43
|
+
This session did not modify code, investigation only
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Extract shared order ledger derivation (SponsorOrderGrid / order-invoice-pdf) into utils/order-ledger
|
|
2
|
+
|
|
3
|
+
GOAL
|
|
4
|
+
|
|
5
|
+
Current state: the order ledger derivation (ordered rows plus running balance: item +, discount -, fee +, payment -, refund +, payments and refunds interleaved by created) exists twice in openstack-uicore-foundation. SponsorOrderGrid (mapOrderData + calculateBalance) renders it on screen, and order-invoice-pdf buildRows renders it on the invoice PDF. The two copies must stay in sync by hand and have already diverged in three places: quantity filter (grid drops items with missing quantity, PDF defaults them to 1), fee row keys (grid uses fee.id, which is undefined on purchases-api v2 payloads; PDF already uses line_id), and zero-amount discount rows (grid renders them, PDF skips them). These are the numbers a sponsor sees on screen and on their invoice; a future change to one copy is unlikely to reach the other, and the failure mode is a silent mismatch between the two surfaces rather than an error.
|
|
6
|
+
|
|
7
|
+
Target state: a single pure derivation module (src/utils/order-ledger.js) consumed by both renderers, leaving only presentation (MUI vs react-pdf) per consumer. Ref: PR 282 review thread discussion_r3683971969. Pattern reference: summit-admin-reuse-before-build, Duplicate Mapping Tables ("two copies of the same mapping drift silently when one gets updated and the other doesn't").
|
|
8
|
+
|
|
9
|
+
TASKS
|
|
10
|
+
|
|
11
|
+
- Create src/utils/order-ledger.js exporting a pure buildOrderLedger(order) that takes the raw PurchaseV2 payload and returns ordered entries (item, discount, fee, payment, refund, note) carrying raw fields, amounts in cents and a precomputed running balanceCents per entry; no i18n, no date or currency formatting, no react-pdf or MUI imports
|
|
12
|
+
- Centralize the ledger rules in that module: sign conventions, payments and refunds interleaved by created, quantity filter (quantity default 1, exclude 0), row keys from line_id
|
|
13
|
+
- Refactor order-invoice-pdf buildRows into a thin mapper from ledger entries to presentational rows (T.translate labels, currencyAmountFromCents, formatDate with LOC), and drop the now-unused summit parameter
|
|
14
|
+
- Refactor SponsorOrderGrid to consume ledger entries: replace mapOrderData and the mutable calculateBalance accumulator with entry.balanceCents; adopt line_id-based fee row keys and skip zero-amount discount rows
|
|
15
|
+
- Migrate the existing buildRows unit tests to order-ledger tests with raw cents expectations; keep the PDF mapper and render tests; keep SponsorOrderGrid tests green and add assertions for the three behavior fixes
|
|
16
|
+
- Verify sponsor-services grid path still works: normalizeOrder spreads the raw payload so raw fields survive, confirm the order object handed to the grid still carries them
|
|
17
|
+
|
|
18
|
+
ACCEPTANCE CRITERIA
|
|
19
|
+
|
|
20
|
+
- src/utils/order-ledger.js exists, exports buildOrderLedger, and imports nothing from @react-pdf/renderer, @mui or i18n-react
|
|
21
|
+
- The invoice PDF and SponsorOrderGrid produce the same rows and the same running balance for the same raw v2 order, asserted with one shared fixture run against both consumers in the same test suite
|
|
22
|
+
- buildRows no longer takes a summit parameter and all invoice dates remain in LOC
|
|
23
|
+
- SponsorOrderGrid fee rows get unique keys from line_id with a v2 payload (no fee-row-undefined keys)
|
|
24
|
+
- SponsorOrderGrid renders no discount row when discount_in_cents is 0
|
|
25
|
+
- jest passes with 0 failures across the order-invoice-pdf, SponsorOrderGrid and utils suites
|
|
26
|
+
- No visual regression on the sponsor order screen and on the invoice PDF for an order containing items, a discount, fees, payments, refunds and a cancelled item
|
|
27
|
+
|
|
28
|
+
DEVELOPMENT NOTES
|
|
29
|
+
|
|
30
|
+
Key files:
|
|
31
|
+
- src/utils/order-ledger.js (new) - pure derivation module
|
|
32
|
+
- src/components/order-invoice-pdf/helpers.js - buildRows becomes a thin presentational mapper
|
|
33
|
+
- src/components/mui/SponsorOrderGrid/index.js - mapOrderData, calculateBalance and the row rendering loop
|
|
34
|
+
- src/components/order-invoice-pdf/__tests__/order-invoice-pdf.test.js - buildRows tests migrate to the ledger
|
|
35
|
+
|
|
36
|
+
Gotchas:
|
|
37
|
+
- SponsorOrderGrid is published and consumed by sponsor-services; behavior must be preserved except for the three documented fixes
|
|
38
|
+
- normalizeOrder in sponsor-services spreads the raw payload and only adds props (addon_name, discount, amount), so the ledger can read raw fields on both raw and normalized orders; the ledger must never read the added formatted props
|
|
39
|
+
- The grid balance today is a mutable accumulator evaluated in JSX render order; replacing it with precomputed balanceCents also removes a re-render fragility
|
|
40
|
+
- purchases-api v2 fees carry line_id, position, title and amount only - never id
|
|
41
|
+
|
|
42
|
+
Risk: silent number mismatch between screen and invoice if only one consumer is migrated. Mitigation: one shared fixture asserted against both consumers in the same test run, and both consumers migrated in the same PR.
|
|
43
|
+
|
|
44
|
+
Out of scope: sponsor-services normalizeOrder adopting getOrderTotal from uicore utils/money (separate small change), any visual redesign of the grid or the PDF, react-pdf version work.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
UploadInputV3 progress bar does not update during large chunked uploads
|
|
2
|
+
|
|
3
|
+
GOAL
|
|
4
|
+
|
|
5
|
+
Current state: In UploadInputV3, the progress bar for chunked uploads of large files (600MB or more) does not update incrementally during the upload. It shows an early partial value shortly after the transfer starts, then freezes for the remainder of the upload, and only jumps to "Complete" once the transfer finishes. This was confirmed via a screen recording showing the bar pixel-identical for 30+ seconds while chunk upload requests were still actively hitting the file-upload-api backend.
|
|
6
|
+
|
|
7
|
+
Target state: The progress bar advances smoothly and monotonically as chunks complete, regardless of file size, matching the behavior already present in the legacy (V1/V2) DOM-based progress bar.
|
|
8
|
+
|
|
9
|
+
This matters because sponsor users uploading large deliverables (500MB+ video or PDF assets) get no reliable feedback that the upload is progressing. A frozen bar for 30+ seconds looks like a hang and erodes trust in the upload feature, and increases support requests asking whether the upload is stuck.
|
|
10
|
+
|
|
11
|
+
TASKS
|
|
12
|
+
|
|
13
|
+
- Apply the existing _completedBytes anti-stall floor (already used by the legacy DOM progress bar in dropzone/index.js) to the React-facing V3 progress path in dropzone-v3.js, so reported progress can only move forward as chunks complete, never stall or regress between chunk boundaries
|
|
14
|
+
- Cap reported progress at 100 percent and guard against divide-by-zero for zero-size files in that same code path
|
|
15
|
+
- Stop DropzoneJS componentDidUpdate from unconditionally deep-cloning the full dropzone options object on every re-render, since a large chunked upload re-renders the component on every progress tick
|
|
16
|
+
- Add unit tests for the DropzoneV3 uploadprogress bridging covering the floor behavior, the 100 percent cap, and the zero-size file case
|
|
17
|
+
|
|
18
|
+
ACCEPTANCE CRITERIA
|
|
19
|
+
|
|
20
|
+
- Uploading a large file (500MB or more) via UploadInputV3 shows the progress bar advancing incrementally throughout the transfer, not just jumping at the very end
|
|
21
|
+
- New test suite src/components/inputs/upload-input-v3/__tests__/dropzone-v3.test.js passes: 3 tests covering the completed-bytes floor, the 100 percent cap, and the zero-size file case
|
|
22
|
+
- Full existing jest suite passes with no regressions
|
|
23
|
+
- No change to already-uploaded file list rendering, error handling, or async (HTTP 202) polling behavior
|
|
24
|
+
|
|
25
|
+
DEVELOPMENT NOTES
|
|
26
|
+
|
|
27
|
+
Key files:
|
|
28
|
+
src/components/inputs/upload-input-v3/dropzone-v3.js - React bridge between DropzoneJS events and UploadInputV3 callbacks, computes the progress percentage passed to the progress bar
|
|
29
|
+
src/components/inputs/dropzone/index.js - base DropzoneJS component, owns chunked upload plumbing, xhr handling, and the _completedBytes tracking this fix reuses
|
|
30
|
+
src/components/inputs/upload-input-v3/__tests__/dropzone-v3.test.js - new test file covering the fix
|
|
31
|
+
|
|
32
|
+
Gotchas:
|
|
33
|
+
_completedBytes is incremented by chunkSize (default 2000000 bytes) on every chunk's xhr.onload in dropzone/index.js. dropzone-v3.js now reads that same field as a floor instead of duplicating the tracking logic, so the two progress bars (legacy DOM and V3 React) stay consistent with a single source of truth.
|
|
34
|
+
Root cause was confirmed via a Jam.dev screen recording of a real 593MB upload in the sponsor portal, showing the progress bar frozen for 30+ seconds mid-transfer while chunk requests were still completing in the browser's network tab.
|
|
35
|
+
|
|
36
|
+
Risks:
|
|
37
|
+
Risk: componentDidUpdate now skips the options re-merge when djsConfig/postUrl are referentially unchanged, which could mask a case where a consumer mutates djsConfig in place instead of passing a new object.
|
|
38
|
+
Mitigation: djsConfig is already produced via useMemo in UploadInputV3 with stable dependencies, so referential equality holds for the intended usage pattern. Consumers that need the merge to re-run on every render were not relying on that behavior for anything observable.
|
|
39
|
+
|
|
40
|
+
Out of scope:
|
|
41
|
+
No changes to chunk size, concurrency defaults, or the async HTTP 202 polling flow.
|
|
42
|
+
No changes to the legacy V1/V2 DOM-based progress bar, which already had the _completedBytes floor.
|
package/package.json
CHANGED
package/.claude/RESUME.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Claude Code — resume checkpoint
|
|
2
|
-
|
|
3
|
-
Session: d2237004-7a96-4289-9c09-adda5e493f8d
|
|
4
|
-
Written: 2026-08-24T15:07:04.027Z
|
|
5
|
-
Trigger: near-limit
|
|
6
|
-
Ref with your in-progress files: refs/claude/checkpoint-d2237004
|
|
7
|
-
|
|
8
|
-
## To resume
|
|
9
|
-
|
|
10
|
-
claude --resume d2237004-7a96-4289-9c09-adda5e493f8d
|
|
11
|
-
|
|
12
|
-
(or open Claude Code in this directory and run /resume)
|
|
13
|
-
|
|
14
|
-
## Plan (from TodoWrite state)
|
|
15
|
-
|
|
16
|
-
No task list was active; see transcript via the resume command above.
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
Don't want these changes? Resume this session (above), then run
|
|
21
|
-
`/rewind` to roll back the turn's tool edits (bash-made changes
|
|
22
|
-
excluded). refs/claude/checkpoint-d2237004 holds a full snapshot until this session's
|
|
23
|
-
next checkpoint, or for up to ~2 weeks.
|