Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
2480 commits
Select commit Hold shift + click to select a range
5e22c15
Merge pull request #693 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 2, 2026
4a1f059
Merge pull request #691 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 2, 2026
3beecfe
build(deps): bump @prisma/adapter-pg from 7.5.0 to 7.6.0
dependabot[bot] Apr 2, 2026
6eaf656
build(deps): bump @prisma/client from 7.5.0 to 7.6.0
dependabot[bot] Apr 2, 2026
ef0be53
Merge pull request #692 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 2, 2026
a531bfd
chore: remove unused @uploadthing/react dependency and OurFileRouter …
jthrilly Apr 2, 2026
45e19fd
Merge branch 'next' into dependabot/npm_and_yarn/next/prisma/client-7…
jthrilly Apr 2, 2026
aa1da83
Merge pull request #690 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 2, 2026
3663f2e
Merge pull request #695 from complexdatacollective/feat/s3-storage-pr…
jthrilly Apr 2, 2026
4d057e6
fix: initialize NodeDrawer as collapsed when starting with 0 nodes
jthrilly Apr 2, 2026
0af50a0
fix: pedigree connector line rendering and remove biologicalSexVariable
jthrilly Apr 2, 2026
5020a0d
fix: pedigree horizontal scrolling and remove interface padding
jthrilly Apr 2, 2026
121207b
fix: remove About You wizard step and update interaction tests
jthrilly Apr 2, 2026
69629f7
fix: pedigree layout alignment across cross-family structures
jthrilly Apr 2, 2026
9bffc2b
fix: increase pedigree row gap to full node height
jthrilly Apr 2, 2026
c0b2877
fix: skip grandparent checklist items for donors and surrogates
jthrilly Apr 2, 2026
1faa274
chore: fix all lint, typecheck and knip errors
jthrilly Apr 2, 2026
ecacb16
feat: implement disease nomination step with click-to-toggle nodes
jthrilly Apr 2, 2026
af33f9d
docs: pedigree network integration design spec
jthrilly Apr 2, 2026
8ae40c5
docs: pedigree network integration implementation plan
jthrilly Apr 2, 2026
2735c14
feat: add 'adoptive' edge type to pedigree layout system
jthrilly Apr 2, 2026
ac7b12f
refactor: replace adoptionStatus with 'adoptive' edge type
jthrilly Apr 2, 2026
ee5080c
refactor: migrate pedigree store to NcNode/NcEdge format
jthrilly Apr 2, 2026
06b87bb
feat: implement finalization, nomination, and reset flows
jthrilly Apr 2, 2026
7cd693d
test: update all tests for NcNode/NcEdge format
jthrilly Apr 2, 2026
e77ac00
fix: improve grandparent checklist item wording
jthrilly Apr 2, 2026
0378951
feat: add instructional popup after ego cell wizard completion
jthrilly Apr 2, 2026
8f60c0d
update intro text
jthrilly Apr 2, 2026
29a939c
fix: default egg/sperm donor questions to No
jthrilly Apr 2, 2026
f76edfb
fix: show finalization dialog on Next, block if wizard incomplete
jthrilly Apr 2, 2026
f5819a4
fix: right-align single dialog footer button
jthrilly Apr 2, 2026
edd4cfa
fix: update layoutDimensions test to match new row gap multiplier
jthrilly Apr 2, 2026
c69e068
chore: fix knip, test, and lint errors
jthrilly Apr 2, 2026
fbdcf9b
test: update e2e visual snapshots
jthrilly Apr 2, 2026
411ec16
small edit to pedigree
jthrilly Apr 2, 2026
cf0b528
change chromatic project key
jthrilly Apr 2, 2026
b592313
remove reference to family tree
jthrilly Apr 2, 2026
07bb98b
wider dialogs
jthrilly Apr 2, 2026
7112b9a
fix: render adoptive parent edges as dashed lines
jthrilly Apr 2, 2026
4c0a7e7
fix: lint error in appSettings, update e2e snapshots for all browsers
jthrilly Apr 2, 2026
337d796
fix: wizard UX issues — partnership labels, donor defaults, scroll
jthrilly Apr 2, 2026
a7ce948
fix: update gender identity labels to Man/boy and Woman/girl
jthrilly Apr 2, 2026
0d8b975
fix(FieldLabel): support markdown bold formatting for interview form …
buckhalt Apr 2, 2026
bf1dd4b
lint
buckhalt Apr 2, 2026
986f4bc
fix(e2e-test-data): add node shape prop to testDataBuilder
buckhalt Apr 2, 2026
2289593
fix(e2e): update testid to reflect changed section name
buckhalt Apr 2, 2026
ab2259f
fix(e2e-preview-mode): update api response message to match handler
buckhalt Apr 2, 2026
6a2abd7
fix: disable drag cursor on pedigree nodes during scaffolding step
jthrilly Apr 3, 2026
f987139
fix: prevent adding parents to ego's partners
jthrilly Apr 3, 2026
ad6db05
fix(e2e): update snapshots
buckhalt Apr 3, 2026
f39d080
e2e: finish interview, update snapshots, update protocol
buckhalt Apr 3, 2026
31e135a
fix(e2e): add waitfor to goto fixture, update snapshots again
buckhalt Apr 3, 2026
00cafbe
fix(e2e): copy standalone to tmp to fix intermittent race conditions
buckhalt Apr 3, 2026
4dbc1be
fix(e2e): use execFileSync to avoid shell injection in cp commands
buckhalt Apr 3, 2026
15dcb03
fix(e2e): fix flaky tests by waiting for mapbox idle and use serial i…
buckhalt Apr 3, 2026
214f52f
build(deps): bump @aws-sdk/client-s3 from 3.1021.0 to 3.1024.0
dependabot[bot] Apr 6, 2026
87434d0
build(deps-dev): bump chromatic from 16.0.0 to 16.1.0
dependabot[bot] Apr 6, 2026
abc4aac
build(deps): bump fuse.js from 7.1.0 to 7.3.0
dependabot[bot] Apr 6, 2026
4969ae0
build(deps): bump posthog-js from 1.363.6 to 1.364.7
dependabot[bot] Apr 6, 2026
6c409e5
build(deps-dev): bump typescript-eslint from 8.57.2 to 8.58.0
dependabot[bot] Apr 6, 2026
f844139
feat(styles): replace Quicksand with Nunito and leverage wider weight…
jthrilly Apr 8, 2026
49732b9
feat(name-generator-roster): add DataCard, fix sort/filter, refactor …
jthrilly Apr 8, 2026
23b3dc5
perf(name-generator-roster): avoid parent re-renders during drag
jthrilly Apr 8, 2026
081a7b4
significant fixes to Collection (perf)
jthrilly Apr 8, 2026
6087c78
Potential fix for pull request finding 'Useless conditional'
jthrilly Apr 9, 2026
c4c9e1f
fix: reduced-motion hang in Spinner, flaky storybook tests, dialog cl…
jthrilly Apr 9, 2026
8782430
fix(markdown): render heading levels correctly in RenderMarkdown
jthrilly Apr 9, 2026
a1785b9
fix(interview-theme): use sea-green for --link so links render correctly
jthrilly Apr 9, 2026
5a389fb
chore(dev): scaffold TS dev-s3 script with local-s3 container lifecycle
jthrilly Apr 9, 2026
b5d578e
test(e2e): regenerate visual snapshots
jthrilly Apr 9, 2026
2a27953
chore(dev): harden dev-s3 shutdown race and remove-container tolerance
jthrilly Apr 9, 2026
2a0a2fe
feat(dev): create fresco-dev bucket via AWS SDK in dev-s3 script
jthrilly Apr 9, 2026
d6068ff
feat(dev): apply public-read bucket policy in dev-s3 script
jthrilly Apr 9, 2026
096a145
chore(dev): rename dev-s3 volume to avoid MinIO volume collision
jthrilly Apr 9, 2026
cffcfc0
fix(popover): silence Base UI render-prop warning in PopoverTrigger
jthrilly Apr 9, 2026
15f6699
fix(InputField): long single-token values no longer overflow container
jthrilly Apr 9, 2026
3c98dfe
fix(uploadthing): use SDK uploader instead of hand-rolled presigned PUT
jthrilly Apr 9, 2026
45fc949
refactor(auth): consolidate auth modules under lib/auth
jthrilly Apr 9, 2026
4a46d71
fix(uploadthing): proxy preview uploads via UTApi; validate token via…
jthrilly Apr 9, 2026
d172904
chore(uploadthing): remove dead hand-rolled presigning code
jthrilly Apr 9, 2026
ed4adae
fix(name-generator-roster): re-query listbox inside waitFor
jthrilly Apr 9, 2026
9281c70
make minio a required service in example docker config
jthrilly Apr 9, 2026
7fafafd
chore(uploadthing): inline parseUploadThingToken into its only caller
jthrilly Apr 9, 2026
66f7aa3
fix(styles): apply consistent focus ring to native and styled select …
jthrilly Apr 9, 2026
e5c7afe
refactor(participants): remove Delete All button from toolbar
jthrilly Apr 10, 2026
726edaf
feat(participants): make interview count column sortable
jthrilly Apr 10, 2026
2a38f22
feat(participants): use SelectAllHeader for select-all toggle
jthrilly Apr 10, 2026
00e3ce4
feat(participants): redesign import/export section as two-column layout
jthrilly Apr 10, 2026
efb2af6
refactor(participants): simplify import/export cards to stacked layout
jthrilly Apr 10, 2026
f125afa
fix(participants): button width and protocol select in export URLs
jthrilly Apr 10, 2026
d752761
refactor(dashboard): consolidate participants toolbar, improve filter…
jthrilly Apr 10, 2026
3ef1b4d
fix(synthetic-interviews): use correct config for FamilyPedigree stage
jthrilly Apr 10, 2026
1dead6c
refactor(interviews): improve network filter UX with clearer structur…
jthrilly Apr 10, 2026
581b2b0
fix(activity-feed): remove duplicate Data Exported event from updateE…
jthrilly Apr 10, 2026
f43152c
fix(test): increase FilterInteraction waitFor timeout to prevent flak…
jthrilly Apr 10, 2026
35c5ae9
fix: resolve knip, lint, and typecheck errors
jthrilly Apr 10, 2026
5b58cdc
fix(e2e): update tests to match current component behavior
jthrilly Apr 10, 2026
9a9a175
update snapshots
jthrilly Apr 10, 2026
a0b3a3f
Merge pull request #697 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 13, 2026
4b8dc85
Merge pull request #698 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 13, 2026
8c1cbe6
Merge pull request #700 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 13, 2026
e7f2f77
Merge pull request #701 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 13, 2026
60e333c
update stage 16 snapshot
jthrilly Apr 13, 2026
3e01fe3
Merge pull request #699 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 13, 2026
87f4b63
wait for GeoJSON source load before geospatial snapshots
jthrilly Apr 13, 2026
031682d
regenerate snapahots
jthrilly Apr 13, 2026
a1096cb
fix(ci): replace duplicate PR comments with single updated report
jthrilly Apr 13, 2026
a57e8bb
use queryRenderedFeatures for GeoJSON load detection
jthrilly Apr 13, 2026
f28b178
fix(ci): replace PR comment with per-browser status checks
jthrilly Apr 13, 2026
9feb6a0
regenerate interview-webkit visual snapshots
jthrilly Apr 13, 2026
7c35dc5
remove goto options: stability should be handled in waitForStageLoad,…
jthrilly Apr 13, 2026
bd84cd6
build(deps-dev): bump @eslint/js from 9.39.3 to 9.39.4
dependabot[bot] Apr 13, 2026
69e7086
build(deps-dev): bump @chromatic-com/storybook from 5.1.1 to 5.1.2
dependabot[bot] Apr 13, 2026
193f7a0
fix(name-generator): fix external nodes in side panel
buckhalt Apr 13, 2026
da25eba
fix: hide UploadThing prompts when S3 storage is configured
buckhalt Apr 13, 2026
68fd3df
fix(field-hints): correctly render markdown
buckhalt Apr 13, 2026
8d429d3
fix(convex-hulls): support all categorical value formats in convex hulls
buckhalt Apr 13, 2026
84bf5c1
fix(collection): deduplicate keys from external roster to ensure item…
buckhalt Apr 13, 2026
9d8ef37
fix: skip AlterForm/AlterEdgeForm stages when no items exist
jthrilly Apr 13, 2026
69eca9c
refactor silos spec for logical navigation
jthrilly Apr 13, 2026
f631b43
further refactoring of silos spec
jthrilly Apr 13, 2026
e6ac01c
refactor(field-hints): simplify Hint markdown handling
jthrilly Apr 14, 2026
9220699
docs(field-hints): fold hint markdown demo into UsingMarkdown story
jthrilly Apr 14, 2026
17abe0c
handle external nodes in node panel using disconnected Node component
jthrilly Apr 14, 2026
d5c02e3
fix(collection): warn on duplicate keys when building nodes
jthrilly Apr 14, 2026
616e3c8
fix(network-query): bridge categorical scalar/array storage in predicate
jthrilly Apr 14, 2026
3b195cc
fix(sociogram): remove duplicate tab stop and wire keyboard activation
jthrilly Apr 14, 2026
b57bf36
remove spacing from node list inside of node panel
jthrilly Apr 14, 2026
147ef6f
lint
jthrilly Apr 14, 2026
01b7a78
test run passing with shared Page
jthrilly Apr 14, 2026
cb9fce9
e2e(geospatial): unify map readiness into single data-map-idle attribute
jthrilly Apr 14, 2026
578d73e
e2e(sociogram): mock force-simulation worker with deterministic grid
jthrilly Apr 14, 2026
860490f
update snapshots
jthrilly Apr 14, 2026
735332f
Merge pull request #703 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 14, 2026
4dcd432
Merge pull request #702 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 14, 2026
170e5b2
fix(preview-upload): add requiresAuth and bodyFormat to response
buckhalt Apr 14, 2026
f75d3c1
drop bodyFormat prop
buckhalt Apr 14, 2026
052a7b6
export and reuse PresignedUrlWithAssetId type
buckhalt Apr 14, 2026
b985764
replace requiresAuth prop with actual headers client must include
buckhalt Apr 14, 2026
56198e9
improve tests for preview endpoints
buckhalt Apr 14, 2026
17e2de3
fix(e2e): wait for map idle before final capture and simplify form fill
jthrilly Apr 14, 2026
5edf563
fix(e2e): restore correct baselines for stage-18/39 intro pages
jthrilly Apr 14, 2026
480ecc5
fix(e2e): bump actionTimeout to 10s for webkit stability
jthrilly Apr 14, 2026
b54fd3b
fix(e2e): await URL step change in interview.next() and disable modal…
jthrilly Apr 14, 2026
fb122f5
fix(e2e): allow 5% interview screenshot tolerance and drop fillField …
jthrilly Apr 14, 2026
08e131e
fix(modal): run enter animation with duration 0 under reduced motion
jthrilly Apr 14, 2026
1bd3aac
Revert "fix(e2e): allow 5% interview screenshot tolerance and drop fi…
jthrilly Apr 14, 2026
6f5eed8
Revert "fix(e2e): bump actionTimeout to 10s for webkit stability"
jthrilly Apr 14, 2026
a7d1f04
e2e: webkit stability — explicit per-test capture, geospatial paint c…
jthrilly Apr 15, 2026
e7b7f46
attempt to fix checkbox
jthrilly Apr 15, 2026
2d057f8
remove pause
jthrilly Apr 15, 2026
4eed1ba
update baselines
jthrilly Apr 15, 2026
e855961
make final screenshots scroll to bottom for stability
jthrilly Apr 15, 2026
6935db5
full suite pass locally
jthrilly Apr 15, 2026
207863b
update additional baselines
jthrilly Apr 15, 2026
6f5068e
fix: audio and video playback failures in safari
buckhalt Apr 15, 2026
af08b79
Merge pull request #705 from complexdatacollective/fix/preview-upload
buckhalt Apr 15, 2026
5310583
further baseline updates to remove focus stages
jthrilly Apr 15, 2026
31db322
all interview tests passing
jthrilly Apr 15, 2026
55a7bf7
correct comment about .mov and .ogg files
buckhalt Apr 15, 2026
3f2d53f
Update lib/interviewer/Interfaces/Information/Information.tsx
buckhalt Apr 15, 2026
06cf090
add maxDiffPixels: 100 for small rendering differences in CI
jthrilly Apr 16, 2026
e80de32
fix(e2e): webkit stability — fillField retry, one-shot style injectio…
jthrilly Apr 16, 2026
d05edd8
fix: useAnimate bypasses MotionConfig.skipAnimations, breaking WebKit…
jthrilly Apr 16, 2026
5ff7d13
Merge pull request #707 from complexdatacollective/fix/video-audio-we…
jthrilly Apr 16, 2026
549b888
further baseline upadates
jthrilly Apr 16, 2026
91d892b
returning to earlier state
jthrilly Apr 17, 2026
4fe2c9b
wip(e2e): narrow testMatch to silos-protocol only
jthrilly Apr 17, 2026
f591b15
refactor(e2e): simplify TestDatabase to testcontainer + migrations
jthrilly Apr 17, 2026
9a7ba86
refactor(e2e): simplify AppServer to single fixed-port instance
jthrilly Apr 17, 2026
9b45c49
refactor(e2e): add minimal AppSettings seed helper
jthrilly Apr 17, 2026
90c5799
refactor(e2e): single-instance global setup
jthrilly Apr 17, 2026
d815dcf
fix(e2e): drop unused no-var eslint-disable in global-setup
jthrilly Apr 17, 2026
03bc235
refactor(e2e): single-instance global teardown
jthrilly Apr 17, 2026
7fbd8d8
refactor(e2e): minimal playwright config — three projects, serial
jthrilly Apr 17, 2026
b784202
refactor(e2e): minimal base test — prisma worker fixture only
jthrilly Apr 17, 2026
9d8ae9c
refactor(e2e): interview-test reads E2E_ASSET_URL from env, owns VISU…
jthrilly Apr 17, 2026
2886701
refactor(e2e): drop database fixture usage from silos-protocol spec
jthrilly Apr 17, 2026
1447352
refactor(e2e): replace docker/local scripts with minimal run-e2e.sh
jthrilly Apr 17, 2026
8933d7c
refactor(e2e): drop test:e2e:local script
jthrilly Apr 17, 2026
87adf17
refactor(e2e): delete obsolete layer-1 infrastructure files
jthrilly Apr 17, 2026
a7ad18a
fix(e2e): use object type for empty fixtures generic
jthrilly Apr 17, 2026
0aacde4
refactor(e2e): delete out-of-scope specs and orphaned snapshot baselines
jthrilly Apr 17, 2026
bc27eb8
ci(e2e): simplified workflow — single run, gh-pages by branch, PR com…
jthrilly Apr 17, 2026
6c7dcfa
chore(e2e): delete existing visual baselines before regeneration
jthrilly Apr 17, 2026
92623da
fix(e2e): drop per-worker protocol.cleanup — leaves orphan Asset rows…
jthrilly Apr 17, 2026
7af243a
chore(e2e): firefox full baselines + webkit partial baselines through…
jthrilly Apr 17, 2026
6eecc4b
fix(dnd): pin activeDropTargetId from keyboard-nav index, not element…
jthrilly Apr 17, 2026
aefc01e
chore(e2e): webkit baselines for stages past DnD fix
jthrilly Apr 17, 2026
61baaf5
chore: resolve knip + lint cleanup
jthrilly Apr 17, 2026
68eb5d2
fix(ci): testcontainers host override + reclaim artifact ownership
jthrilly Apr 17, 2026
dc2c21b
ci: provide Postgres service for build-time queries
jthrilly Apr 17, 2026
1008358
fix(app): keep root-layout analytics dynamic so Docker image builds w…
jthrilly Apr 17, 2026
16ed1ed
test(e2e): add captureFinal() to female-ineligibility stages + baselines
jthrilly Apr 17, 2026
1eb10f7
test(e2e): mark Stage 8 Geospatial Interface as slow on webkit
jthrilly Apr 17, 2026
37ca4cf
add test.slow to all geospatial interfaces
jthrilly Apr 17, 2026
f81bff0
fix(e2e): bump interview.next() waitForURL to 20s for WebKit headroom
jthrilly Apr 17, 2026
13ecf1a
Merge pull request #710 from complexdatacollective/refactor/e2e-simplify
jthrilly Apr 17, 2026
8d2b9bc
refactor ut preview mode flow to use direct presigned urls
buckhalt Apr 16, 2026
3227151
add ut presigned file previously implemented
buckhalt Apr 16, 2026
1401f7e
refactor: move uploadthing token util and type to shared file
buckhalt Apr 16, 2026
f8e4133
fix(tests): update preview handler test to direct ut upload
buckhalt Apr 17, 2026
2e733c8
rm passing ut version, zod validate token shape
buckhalt Apr 17, 2026
03c4b39
Merge pull request #711 from complexdatacollective/fix/preview-upload…
jthrilly Apr 20, 2026
6c091c1
remove quicksand fonts
jthrilly Apr 20, 2026
6451065
fix(RenderMarkdown): drop useRender to avoid ref-on-Fragment warning
jthrilly Apr 20, 2026
7ea476f
feat(form): wire min/max validation for DatePicker, fix timezone bugs
jthrilly Apr 20, 2026
6a1c10a
build(deps-dev): bump prettier from 3.8.2 to 3.8.3
dependabot[bot] Apr 20, 2026
cf8cff1
build(deps-dev): bump knip from 6.4.1 to 6.5.0
dependabot[bot] Apr 20, 2026
6ea063e
build(deps): bump nanoid from 5.1.7 to 5.1.9
dependabot[bot] Apr 20, 2026
32fa2d9
build(deps): bump postcss from 8.5.9 to 8.5.10
dependabot[bot] Apr 20, 2026
930e1a3
fix(RelativeDatePicker): forward Field's onBlur to the native input
jthrilly Apr 20, 2026
dc23875
build(deps): bump @tiptap/pm from 3.22.3 to 3.22.4
dependabot[bot] Apr 20, 2026
e5251cf
fix(RadioGroup): forward Field's onBlur so validation fires on blur
jthrilly Apr 20, 2026
d3e79b0
test(e2e): update visual snapshots
jthrilly Apr 20, 2026
003c086
fix(e2e): isolate container node_modules from host bind mount
jthrilly Apr 20, 2026
88fb855
ci(chromatic): run on all branch pushes
jthrilly Apr 20, 2026
4acf49b
ci(e2e): stop double-running on next branch with open PR
jthrilly Apr 20, 2026
6c88e72
test(e2e): update visual snapshots
jthrilly Apr 20, 2026
e93efbc
Merge pull request #712 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 20, 2026
94acb15
Merge pull request #713 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 20, 2026
e8faa1a
Merge pull request #714 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 20, 2026
783b5d6
Merge pull request #715 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 20, 2026
2e00200
Merge pull request #716 from complexdatacollective/dependabot/npm_and…
jthrilly Apr 20, 2026
8834b67
fix(categorical-bin): treat falsy attributes as categorized
buckhalt Apr 20, 2026
3398aef
disable animations in chromatic
jthrilly Apr 20, 2026
5a378db
test(categorical-bin): add test for uncategorized and refactor for te…
buckhalt Apr 20, 2026
eed8509
remove unneeded test case
buckhalt Apr 20, 2026
0a56276
refactor: use isNil instead of != null
buckhalt Apr 20, 2026
23b9a60
treat empty arrays as unset, add missing import, fix spelling
buckhalt Apr 20, 2026
537ecef
fix(network-query): treat stored 0 and false as set in INCLUDES and E…
buckhalt Apr 20, 2026
732b20b
fix(network-exporters): treat 0/false as selected in isCategoricalOpt…
buckhalt Apr 20, 2026
fa2edd5
fix(categorical-bin): size circles to content box when a bin is expanded
buckhalt Apr 20, 2026
5064ffc
Update lib/interviewer/Interfaces/CategoricalBin/useCircleLayout.ts
buckhalt Apr 20, 2026
6ec67f2
fix(EncryptedBackground): render deterministic static state under Chr…
jthrilly Apr 21, 2026
5c0c108
chore(storybook): disable chromatic snapshot for AnimatedProgress story
jthrilly Apr 21, 2026
568280a
fix(storybook): import theme CSS statically so Chromatic snapshots ar…
jthrilly Apr 21, 2026
ed3cfd4
test(useProtocolForm): pin RelativeDatePicker anchor date in mock pro…
jthrilly Apr 21, 2026
1c93849
fix(dialog): prevent focus auto-scroll from hiding dialog header
jthrilly Apr 21, 2026
47a8732
fix(storybook): toggle data-interview on document.body instead of Rea…
jthrilly Apr 21, 2026
51dfba3
fix(scroll-nudge): latch scrolled-to-bottom so the ready pulse persists
jthrilly Apr 21, 2026
ffe4c4e
fix(categorical-bin): shrink expanded panel size as bin count grows
buckhalt Apr 21, 2026
c67edc5
test: remove categorical false value cases
buckhalt Apr 21, 2026
5a84a56
fix(validation): exclude currently editing entity from unique checks
buckhalt Apr 21, 2026
d1e9a08
fix(validation): memoize merged validationContext to prevent field re…
buckhalt Apr 21, 2026
bdbb63a
update snapshots
buckhalt Apr 22, 2026
f5ca0ea
update snapshots stage 27
buckhalt Apr 22, 2026
9fa93f0
Merge pull request #717 from complexdatacollective/fix/categorical-bi…
buckhalt Apr 22, 2026
3cf58fc
Merge pull request #718 from complexdatacollective/fix/categorical-bi…
buckhalt Apr 22, 2026
6f1f7ed
Merge pull request #719 from complexdatacollective/fix/unique-validat…
buckhalt Apr 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
335 changes: 335 additions & 0 deletions .claude/skills/generate-e2e-tests/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
---
name: generate-e2e-tests
description: Generate comprehensive Playwright e2e tests from a .netcanvas protocol file and an optional recording. Invoke with /generate-e2e-tests <protocol-path> [recording-path]
user-invocable: true
---

# Generate E2E Tests from Protocol

You are generating comprehensive Playwright e2e tests for a Fresco interview protocol.

## Inputs

- **Protocol path**: `$1` — path to a `.netcanvas` file (ZIP containing `protocol.json`)
- **Recording path** (optional): `$2` — path to a recording directory (contains `actions.jsonl`, `SESSION.md`, `screenshots/`)

If no recording is provided, generate a **synthetic happy path** using the data generation strategies in STAGE_TEST_REFERENCE.md (see "Synthetic Data Generation" section).

## Step 1: Read Reference Materials

Read these files to understand the testing infrastructure and patterns:

1. `tests/e2e/docs/STAGE_TEST_REFERENCE.md` — what to test for each stage type, fixture availability, validation testing patterns
2. `tests/e2e/fixtures/stage-fixture.ts` — available fixture methods and their signatures
3. `tests/e2e/fixtures/interview-fixture.ts` — interview navigation fixture
4. `tests/e2e/fixtures/protocol-fixture.ts` — protocol installation and network state inspection
5. `tests/e2e/CLAUDE.md` — full e2e testing architecture guide
6. `tests/e2e/specs/interview/silos-protocol.spec.ts` — reference test implementation to match style/structure
7. `CLAUDE.md` — project coding conventions (path aliases, TypeScript, etc.)

## Step 2: Extract and Analyze Protocol

Extract the protocol JSON:

```bash
unzip -p "$1" protocol.json
```

From the extracted JSON, build a **stage map** — for each stage (by index), extract:

- `type` — stage type (e.g., `NameGeneratorQuickAdd`, `EgoForm`, `Sociogram`)
- `label` — display label
- `subject` — `{ entity, type }` pointing to codebook entry (null for Information/Anonymisation)
- `introductionPanel` — title and text (if present)
- `form.fields[]` — array of `{ variable }` referencing codebook variables
- `prompts[]` — array of prompt objects (with `createEdge`, `variable`, `highlight`, etc.)
- `panels[]` — side panel configuration
- `behaviours` — `maxNodes`, `minNodes`, `freeDraw`, etc.

For each form field, resolve the variable UUID against the codebook:

- Look up `codebook.[entity].[type].variables.[variableId]`
- Extract: `name`, `type`, `component`, `validation`, `options`

This gives you the field name (UUID), display name, input component type, validation rules, and available options for each form field.

## Step 3: Analyze Recording (if provided)

If `$2` is provided, read `$2/actions.jsonl` (one JSON object per line).

Group actions by stage — track URL changes via the `step=N` query parameter. For each stage visited:

- Extract the sequence of user actions (click, fill, press, select)
- Note filled values and selected options
- Note which nodes were created (names entered in quick-add or name generator forms)
- Note edge-creating interactions (sociogram clicks, dyad census selections)

The recording represents the **happy path** — the exact user journey to replay.

### If no recording

Generate a synthetic happy path from the protocol alone:

1. Walk through all stages in order (index 0 to N)
2. For each stage, use the **Synthetic Data Generation** section of STAGE_TEST_REFERENCE.md to determine what values to fill, how many nodes to create, etc.
3. For conditional/skip logic, choose the path that visits the **most stages**
4. Track synthetic state as you go — node names created on earlier stages are needed for bin/census/sociogram stages later

## Step 4: Generate Test File

Create `tests/e2e/specs/interview/<protocol-name>.spec.ts` where `<protocol-name>` is derived from the protocol name (kebab-case, lowercase).

### File Structure

Follow this exact pattern (from the reference implementation):

```typescript
/**
* <Protocol Name> Tests
*
* Tests interview stage navigation using a real .netcanvas protocol file.
*/

import path from 'node:path';
import { expect, test } from '~/tests/e2e/fixtures/interview-test.js';
import { expectURL } from '~/tests/e2e/helpers/expectations.js';

const PROTOCOL_PATH = path.resolve(
import.meta.dirname,
'../../data/<filename>.netcanvas',
);

let sharedProtocolId: string;

test.describe('<Protocol Name>', () => {
test.beforeAll(async ({ database, protocol }) => {
await database.restoreSnapshot();
const { protocolId } = await protocol.install(PROTOCOL_PATH);
sharedProtocolId = protocolId;
});

test.describe('Happy Path', () => {
test.describe.configure({ mode: 'serial' });

let interviewId: string;

test.beforeAll(async ({ protocol }) => {
interviewId = await protocol.createInterview(sharedProtocolId);
});

test.beforeEach(({ interview }) => {
interview.interviewId = interviewId;
});

test.afterEach(async ({ page, interview }) => {
const stepMatch = /step=(\d+)/.exec(page.url());
if (stepMatch?.[1]) {
const step = stepMatch[1];
// List stage indices with non-deterministic rendering
const highToleranceStages: string[] = [/* sociogram indices */];

await interview.capture(`stage-${step}-final`, {
maxDiffPixelRatio: highToleranceStages.includes(step)
? 0.1
: undefined,
});
}
});

// One test() per stage...
});
});
```

### Per-Stage Test Generation

For each stage in the protocol, generate a `test()` block. Use the STAGE_TEST_REFERENCE.md to determine what to test.

#### Mapping Recording Actions to Fixture Calls

Translate recording actions to fixture method calls using these mappings:

| Recording Pattern | Fixture Call |
|---|---|
| Navigate to URL with `step=N` | `interview.goto(N)` |
| Click element matching next/forward button | `interview.nextButton.click()` |
| Fill input within `[data-field-name="UUID"]` | `stage.form.fillText(UUID, value)` or `fillNumber`/`fillDate` based on codebook component |
| Click radio within `[data-field-name="UUID"]` | `stage.form.selectRadio(UUID, optionLabel)` |
| Click checkbox within `[data-field-name="UUID"]` | `stage.form.selectCheckbox(UUID, optionLabel)` |
| Click toggle button within `[data-field-name="UUID"]` | `stage.form.selectToggleButton(UUID, optionLabel)` |
| Fill quick-add input + press Enter | `stage.quickAdd.addNode(value)` |
| Click "Add a person" button | `stage.nameGenerator.openAddForm()` |
| Click "Finished" button in dialog | `stage.nameGenerator.submitForm()` |
| Drag node from panel | `stage.nodePanel.dragNodeToMainList(label)` |
| Click node on sociogram (connecting) | `stage.sociogram.connectNodes(from, to)` |
| Drag node to ordinal bin | `stage.ordinalBin.dragNodeToBin(node, bin)` |
| Drag node to categorical bin | `stage.categoricalBin.dragNodeToBin(node, bin)` |

#### Determine Form Method from Codebook

Use the codebook variable's `component` (or `type` if no component) to pick the right form fixture method:

| Component | Method |
|---|---|
| `Text`, `TextArea` | `fillText` |
| `Number` | `fillNumber` |
| `DatePicker` | `fillDate` |
| `RadioGroup` | `selectRadio` |
| `LikertScale` | `selectLikert` |
| `CheckboxGroup` | `selectCheckbox` |
| `ToggleButtonGroup` | `selectToggleButton` |
| `Boolean` | `selectRadio` (options are "Yes"/"No" or custom labels from codebook) |

#### Comments

Add a comment above each form field interaction with the field's display name and component type:

```typescript
// 1. Date of birth (DatePicker)
await stage.form.fillDate('596c2ac2-...', '2000-06-15');

// 2. Gender identity (RadioGroup)
await stage.form.selectRadio('a06f06f5-...', 'Cisgender Male');
```

### Validation Tests

For each form stage (EgoForm, AlterForm, AlterEdgeForm), examine the codebook variables for targeted validation rules. Generate validation test assertions **within the happy path test** for that stage:

1. **Before filling fields**: Try to advance, verify validation blocks:
```typescript
// Verify validation blocks advancement
await interview.nextButton.click();
await expectURL(page, /step=N/); // Still on same stage

// Verify required field errors
await expect(
stage.form.getFieldError('field-uuid'),
).toBeVisible();
```

2. **Then fill fields normally** from the recording data.

Only test these validations (skip others):
- `required: true` — always test
- `minValue` / `maxValue` — test if present
- `minLength` / `maxLength` — test if present
- `pattern` — test if present
- `unique` — test if applicable (needs duplicate value scenario)
- `sameAs` / `differentFrom` — test if present

### Network State Verification

The sync middleware uses a 3-second debounce with leading+trailing edges. Each `interview.goto()` destroys the current page, killing any pending trailing-edge syncs. Stages that set data used by downstream skip logic or filtering must explicitly wait for that data to persist.

#### Form stages (EgoForm, AlterForm) must click Next to submit

Form data lives in React Hook Form's local state until the form is submitted. **You must click `interview.nextButton` at the end of every form stage** to flush the data to Redux. Without this, the sync middleware never sees the data.

For **EgoForm** stages, click Next as the last interaction (replaces the `toBeEnabled` assertion):

```typescript
// Submit form to flush data to Redux
await interview.nextButton.click();
```

For **AlterForm** stages with slides, click Next after filling the **last slide** (the earlier slides already submit when you click Next to advance):

```typescript
// Submit last slide to flush form data to Redux
await interview.nextButton.click();
```

Note: clicking Next navigates to the next stage, so the `afterEach` screenshot will capture the next stage's initial state rather than the current stage's final state.

#### Persistence waits for skip logic

After stages that set attributes consumed by downstream skip logic or filtering, add explicit waits using the protocol fixture. Available methods:

- `protocol.waitForNodes(interviewId, expectedCount)` — after node creation stages
- `protocol.waitForNode(interviewId, nodeName)` — when count alone is ambiguous
- `protocol.waitForNodeAttribute(interviewId, nodeName, attributeId)` — after CategoricalBin, OrdinalBin, or AlterForm stages (checks for non-null value)
- `protocol.waitForEgoAttribute(interviewId, attributeId, expectedValue)` — after EgoForm stages

Example for a CategoricalBin stage with downstream skip logic:

```typescript
test('Stage N: CategoricalBin', async ({ interview, stage, protocol }) => {
await interview.goto(N);

await stage.categoricalBin.dragNodeToBin('Dan', 'Yes');
await stage.categoricalBin.dragNodeToBin('Alice', 'No');

await expect(interview.nextButton).toBeEnabled();

// Wait for the LAST categorized node's attribute to persist
await protocol.waitForNodeAttribute(
interview.interviewId,
'Alice',
'variable-uuid',
);
});
```

**Always add `protocol` to the test's destructured fixtures** when using persistence waits.

### Stages With Placeholder Fixtures

Check the Fixture Availability Summary in STAGE_TEST_REFERENCE.md. If a stage type's fixture is marked **Placeholder**, generate a minimal test with a TODO referencing the placeholder:

```typescript
test('Stage N: Stage Label', async ({ page, interview }) => {
await interview.goto(N);

// TODO: stage.dyadCensus is a placeholder fixture — implement its
// interaction methods before writing full test assertions.
// See DyadCensusFixture JSDoc in stage-fixture.ts for the methods needed.
//
// Expected behavior from recording:
// - Dismiss intro panel
// - Select Yes/No for each node pair
// - Auto-advances after 350ms
});
```

Always reference the `stage.<fixtureName>` property (e.g., `stage.dyadCensus`, `stage.narrative`) so the test structure is ready — it just needs the fixture methods implemented. Never use raw Playwright selectors as a fallback.

### Skipped Stages

If the recording skips certain stage indices (e.g., conditional stages), add a comment:

```typescript
// Stages N-M are skipped (conditional on <condition from codebook>)
```

### Browser-Specific Skips

Add `test.skip()` for known browser limitations:

```typescript
// Skip geospatial on Firefox (no WebGL in Playwright's Firefox)
test.skip(browserName === 'firefox', 'Firefox lacks WebGL support in Playwright');
```

## Step 5: Verify Protocol File Location

Check if the `.netcanvas` file is already in `tests/e2e/data/`. If not, suggest copying it there and update the path constant accordingly.

## Step 6: Output Summary

After generating the test file, output:
1. Path to the generated test file
2. Number of stages covered
3. Number of validation tests included
4. List of stages with TODO placeholders (missing fixtures)
5. Suggested next steps (copy protocol to test data, run tests, etc.)

## Important Rules

- **Always use path aliases** (`~/tests/e2e/...`) for imports, never relative paths
- **Use `.js` extensions** in import paths (TypeScript with ESM)
- **Field names are UUIDs** — always use the variable UUID from the codebook, not the display name
- **Serial mode** — interview tests MUST use `test.describe.configure({ mode: 'serial' })`
- **Soft assertions for screenshots** — the `afterEach` capture pattern handles this via `interview.capture()`
- **No `console.log`** — project ESLint rule forbids it
- **Follow existing patterns** — match the style, structure, and conventions of `silos-protocol.spec.ts` exactly
20 changes: 7 additions & 13 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
# -------------------
# Required environment variables
# -------------------
DATABASE_URL="postgres://user:password@host:5432/database?schema=public" # A pooled connection URL for Prisma.
DATABASE_URL_UNPOOLED="postgres://user:password@host:5432/database?schema=public" # A non-pooling connection URL for Prisma

# -------------------
# Optional environment variables - uncomment to use
# -------------------

#DISABLE_ANALYTICS # true or false - If true, the app will not send anonymous analytics and error data. Defaults to false.
#SANDBOX_MODE=false # true or false - if true, the app will use the sandbox mode, which disables resetting the database and other features
#PUBLIC_URL="http://yourdomain.com" # When using advanced deployment, this is required. Set to the domain name of your app
#INSTALLATION_ID="your-app-name" # A unique identifier for your app, used for analytics. Generated automatically if not set.
#USE_NEON_POSTGRES_ADAPTER=false # true or false - If true, uses Neon serverless PostgreSQL adapter instead of standard pg adapter. Required for Vercel/Netlify deployments with Neon. Defaults to false.

# -------------------
# Required environment variables
# -------------------

POSTGRES_USER="postgres" # Your PostgreSQL username
POSTGRES_PASSWORD="postgres" # Your PostgreSQL password
POSTGRES_DATABASE="postgres" # Your PostgreSQL database name
POSTGRES_HOST="postgres" # Your PostgreSQL host
DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/${POSTGRES_DATABASE}?schema=public" # A pooled connection URL for Prisma.
DATABASE_URL_UNPOOLED="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/${POSTGRES_DATABASE}?schema=public" # A non-pooling connection URL for Prisma
#USE_NEON_POSTGRES_ADAPTER=false # true or false - If true, uses Neon serverless PostgreSQL adapter instead of standard pg adapter. Required for Vercel/Netlify deployments with Neon. Defaults to false.
Loading
Loading