Skip to content

Commit 95906f6

Browse files
committed
feat: add virtualization for schema section
1 parent 6e8ce24 commit 95906f6

11 files changed

Lines changed: 546 additions & 163 deletions

File tree

.claude/implementation/perf-virtualization/phase-1-models-virtualization.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,39 +76,39 @@ component renders instead of this one.
7676

7777
## Acceptance Criteria
7878

79-
- [ ] A spec **below** the 100-schema threshold renders today's markup unchanged (legacy path) —
79+
- [x] A spec **below** the 100-schema threshold renders today's markup unchanged (legacy path) —
8080
verify `model-collapse.cy.js` passes with no edits
81-
- [ ] A spec **above** the threshold uses the windowed path, and only visible models in the viewport
81+
- [x] A spec **above** the threshold uses the windowed path, and only visible models in the viewport
8282
are mounted (verify in React DevTools)
83-
- [ ] Boundary tested both sides — one fixture just under the threshold, one just over
84-
- [ ] Scrolling through the models list renders/unmounts items correctly
85-
- [ ] Collapsing and expanding the "Schemas/Models" section works as before
86-
- [ ] Existing `model-collapse.cy.js` scenarios still pass **with no edits** — its fixtures have 3
83+
- [x] Boundary tested both sides — one fixture just under the threshold, one just over
84+
- [x] Scrolling through the models list renders/unmounts items correctly
85+
- [x] Collapsing and expanding the "Schemas/Models" section works as before
86+
- [x] Existing `model-collapse.cy.js` scenarios still pass **with no edits** — its fixtures have 3
8787
definitions each, so they take the legacy path. If any of its selectors needed changing
8888
(`.models h4 .models-control`, `#model-User .model-box .model-box-control` at `:40`/`:44`,
8989
`#model-Pet` / `#model-Order` at `:18`/`:28`/`:34`), that means the legacy path was altered —
9090
treat it as a regression, not a test to update
91-
- [ ] `defaultModelsExpandDepth < 0` still short-circuits the whole section to `null`
91+
- [x] `defaultModelsExpandDepth < 0` still short-circuits the whole section to `null`
9292
(`models.jsx:51`), and `defaultModelsExpandDepth > 0 && isShown` still drives initial
9393
per-model expansion (`models.jsx:131`)
9494
- [ ] No visual regression — layout, spacing, expand/collapse of individual model unchanged
95-
- [ ] No accessibility regression — keyboard navigation and screen reader order preserved
96-
- [ ] Performance: initial render time for the 200+ model fixture reduced vs. the recorded baseline
95+
- [x] No accessibility regression — keyboard navigation and screen reader order preserved
96+
- [x] Performance: initial render time for the 200+ model fixture reduced vs. the recorded baseline
9797
(React Profiler, before/after)
98-
- [ ] Unit tests updated in `test/unit/core/plugins/json-schema-5/components/models.jsx`
99-
- [ ] `ResizeObserver` polyfill added to `test/unit/jest-shim.js` and `npm run test:unit` green
98+
- [x] Unit tests updated in `test/unit/core/plugins/json-schema-5/components/models.jsx`
99+
- [x] `ResizeObserver` polyfill added to `test/unit/jest-shim.js` and `npm run test:unit` green
100100
(blocking prerequisite — see Unit-test infrastructure)
101101
- [ ] Bundle-size impact recorded via `npm run deps-size` before/after; `@tanstack/react-virtual`
102102
adds ~5KB min+gzip. Flag it in the PR if the measured delta is materially larger
103-
- [ ] `swagger-ui-react` still renders models correctly — the flavor re-exports core, so it
103+
- [x] `swagger-ui-react` still renders models correctly — the flavor re-exports core, so it
104104
inherits this change with no code edit, but it is a separately published package and is not
105105
covered by the Cypress suite
106-
- [ ] E2E test: models section scrolls and renders correctly with the new fixture
107-
- [ ] `#model-<Name>` browser-anchor navigation still works below the threshold, and its
106+
- [x] E2E test: models section scrolls and renders correctly with the new fixture
107+
- [x] `#model-<Name>` browser-anchor navigation still works below the threshold, and its
108108
above-threshold breakage is accepted per
109109
[Accepted Behavior Changes](#accepted-behavior-changes-confirm-with-maintainers-before-building).
110110
Note this is the plain browser anchor — model *deep linking* does not exist (see Technical Notes)
111-
- [ ] Expanding model A, scrolling it out of view, and scrolling back shows A still expanded and
111+
- [x] Expanding model A, scrolling it out of view, and scrolling back shows A still expanded and
112112
no *other* model wrongly expanded (guards the `getItemKey` requirement below)
113113

114114
## Technical Notes

package-lock.json

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"dependencies": {
7777
"@babel/runtime-corejs3": "^7.27.1",
7878
"@scarf/scarf": "=1.4.0",
79+
"@tanstack/react-virtual": "=3.14.9",
7980
"base64-js": "^1.5.1",
8081
"buffer": "^6.0.3",
8182
"classnames": "^2.5.1",

src/core/plugins/deep-linking/layout.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import Im, { fromJS } from "immutable"
55

66
const SCROLL_TO = "layout_scroll_to"
77
const CLEAR_SCROLL_TO = "layout_clear_scroll"
8+
const SCROLL_TO_VIRTUALIZED_SCHEMA = "layout_scroll_to_virtualized_schema"
9+
const CLEAR_SCROLL_TO_VIRTUALIZED_SCHEMA = "layout_clear_scroll_to_virtualized_schema"
810

911
export const show = (ori, { getConfigs, layoutSelectors }) => (...args) => {
1012
ori(...args)
@@ -133,6 +135,15 @@ export const clearScrollTo = () => {
133135
}
134136
}
135137

138+
export const scrollToVirtualizedSchema = (name) => ({
139+
type: SCROLL_TO_VIRTUALIZED_SCHEMA,
140+
payload: name,
141+
})
142+
143+
export const clearScrollToVirtualizedSchema = () => ({
144+
type: CLEAR_SCROLL_TO_VIRTUALIZED_SCHEMA,
145+
})
146+
136147
// From: https://stackoverflow.com/a/42543908/3933724
137148
// Modified to return html instead of body element as last resort
138149
function getScrollParent(element, includeHidden) {
@@ -166,12 +177,17 @@ export default {
166177
scrollTo,
167178
clearScrollTo,
168179
readyToScroll,
169-
parseDeepLinkHash
180+
parseDeepLinkHash,
181+
scrollToVirtualizedSchema,
182+
clearScrollToVirtualizedSchema,
170183
},
171184
selectors: {
172185
getScrollToKey(state) {
173186
return state.get("scrollToKey")
174187
},
188+
getScrollToVirtualizedSchema(state) {
189+
return state.get("scrollToVirtualizedSchema")
190+
},
175191
isShownKeyFromUrlHashArray(state, urlHashArray) {
176192
const [tag, operationId] = urlHashArray
177193
// We only put operations in the URL
@@ -199,7 +215,13 @@ export default {
199215
},
200216
[CLEAR_SCROLL_TO](state) {
201217
return state.delete("scrollToKey")
202-
}
218+
},
219+
[SCROLL_TO_VIRTUALIZED_SCHEMA](state, action) {
220+
return state.set("scrollToVirtualizedSchema", action.payload)
221+
},
222+
[CLEAR_SCROLL_TO_VIRTUALIZED_SCHEMA](state) {
223+
return state.delete("scrollToVirtualizedSchema")
224+
},
203225
},
204226
wrapActions: {
205227
show

0 commit comments

Comments
 (0)