feat(versioning): list-view collapse with include_history toggle (Phase 2)#447
Merged
Conversation
This was referenced May 27, 2026
363467b to
0d2da07
Compare
bc07763 to
fb74752
Compare
larsgeorge-db
added a commit
that referenced
this pull request
May 28, 2026
… EntityVersionPicker (PRD #442 phase 3) Phase 3 of the unified version-family work. Three vertically-aligned slices: 1. **Role-aware visibility ranking** — adds `src/common/version_visibility.py` with elevated vs consumer status rank tables and a `collapse_by_family` helper. Plumbed into the contracts and products list managers so the family representative is picked according to the caller's role: * Consumer: ACTIVE > DEPRECATED (drafts hidden entirely) * Owner / team member / subscriber / admin: DRAFT > PROPOSED > UNDER_REVIEW > APPROVED > ACTIVE > DEPRECATED Subscription-based elevation is wired in for products via the existing `DataProductSubscriptionDb` table; contracts use ownership only (no subscription table today). 2. **Family-latest resolver endpoints** — `GET /api/data-contracts/families/{family_id}/latest` and the products counterpart. These resolve a family-follow-latest reference to a concrete row using the same role-aware rank, so any caller storing only a family id can read back the right version. 3. **EntityVersionPicker** — new shared component in `components/common/entity-version-picker.tsx`. Combobox over the collapsed list endpoint (one row per family with inline version badges), optional Entity-pinned / Family-follow-latest scope toggle, and an inline sub-picker for refining the version when pinning. The `link-contract-to-port-dialog` (closes #69) is migrated as the first call site, with `allowedScopes=['entity']` until the output-port reference-storage slice lands. Tests added: * `test_version_visibility.py` — 12 cases covering status visibility, rank ordering, tie-breaks, and the consumer-only / admin-only edges. * `test_version_family.py` — two new manager-level cases proving consumers see the active rep while team members of the same family see the in-flight draft. Note: the dev backend reloader has a pre-existing misconfiguration (noted in PR #447). Logic is covered by unit tests; live verification requires a manual `uvicorn` restart.
…se 2) Make the data-contracts and data-products list views show one row per version_family_id by default, with a "Show all versions" toggle that expands every visible version. Each collapsed row surfaces a small "N versions" badge so users can see at a glance which entities have history, without paying the row-count cost. Builds on PRD #442 / PR #446 (Phase 1). Backend - DataContractSummary + DataProduct API models gain a `versionCount` (alias `version_count`) field. Populated only on the collapsed view so the expanded view never lies about per-row counts. - DataContractsManager._query_contracts: drop the legacy base_name Python-side dedupe in favor of canonical version_family_id grouping, and return (rows, family_counts) so the builder can attach counts without a second query. Same shape feeds both collapsed and include_history paths. - DataContractsManager._build_contract_summaries now accepts an optional family_counts map and emits parent/family/draft/changeSummary fields that were previously left null on the summary even though they exist on the row. - list_contracts_from_db and the /data-contracts route propagate the include_history flag end-to-end (route was already accepting it). - DataProductsManager.list_products: collapse by version_family_id after the visibility cascade, attach version_count to the surviving row. include_history=True bypasses the collapse and suppresses the count. - /data-products route surfaces include_history. Frontend - DataContractListItem and DataProduct gain `versionCount`. - New components/common/version-count-badge.tsx — compact pill that hides itself for single-version families and otherwise renders a click-through history hint next to the version cell. - data-contracts.tsx and data-products.tsx: family badge next to the version column + "Show all versions" switch in the toolbar; both list-fetch paths plumb include_history through the query string. Tests - 5 new unit tests cover the collapse default, the family-count emission, include_history bypass, and product-side parity. Note: existing dev uvicorn instances have a stale --reload-dir pointing at the pre-Phase-1 src/api layout (see /tmp/backend.log statreload trace). Restart the backend to pick up the new include_history wiring locally.
fb74752 to
0fd78e4
Compare
larsgeorge-db
added a commit
that referenced
this pull request
May 28, 2026
… EntityVersionPicker (PRD #442 phase 3) Phase 3 of the unified version-family work. Three vertically-aligned slices: 1. **Role-aware visibility ranking** — adds `src/common/version_visibility.py` with elevated vs consumer status rank tables and a `collapse_by_family` helper. Plumbed into the contracts and products list managers so the family representative is picked according to the caller's role: * Consumer: ACTIVE > DEPRECATED (drafts hidden entirely) * Owner / team member / subscriber / admin: DRAFT > PROPOSED > UNDER_REVIEW > APPROVED > ACTIVE > DEPRECATED Subscription-based elevation is wired in for products via the existing `DataProductSubscriptionDb` table; contracts use ownership only (no subscription table today). 2. **Family-latest resolver endpoints** — `GET /api/data-contracts/families/{family_id}/latest` and the products counterpart. These resolve a family-follow-latest reference to a concrete row using the same role-aware rank, so any caller storing only a family id can read back the right version. 3. **EntityVersionPicker** — new shared component in `components/common/entity-version-picker.tsx`. Combobox over the collapsed list endpoint (one row per family with inline version badges), optional Entity-pinned / Family-follow-latest scope toggle, and an inline sub-picker for refining the version when pinning. The `link-contract-to-port-dialog` (closes #69) is migrated as the first call site, with `allowedScopes=['entity']` until the output-port reference-storage slice lands. Tests added: * `test_version_visibility.py` — 12 cases covering status visibility, rank ordering, tie-breaks, and the consumer-only / admin-only edges. * `test_version_family.py` — two new manager-level cases proving consumers see the active rep while team members of the same family see the in-flight draft. Note: the dev backend reloader has a pre-existing misconfiguration (noted in PR #447). Logic is covered by unit tests; live verification requires a manual `uvicorn` restart.
3 tasks
larsgeorge-db
added a commit
that referenced
this pull request
May 28, 2026
… EntityVersionPicker (PRD #442 phase 3) (#467) * feat(versioning): role-aware family collapse, family-latest resolver, EntityVersionPicker (PRD #442 phase 3) Phase 3 of the unified version-family work. Three vertically-aligned slices: 1. **Role-aware visibility ranking** — adds `src/common/version_visibility.py` with elevated vs consumer status rank tables and a `collapse_by_family` helper. Plumbed into the contracts and products list managers so the family representative is picked according to the caller's role: * Consumer: ACTIVE > DEPRECATED (drafts hidden entirely) * Owner / team member / subscriber / admin: DRAFT > PROPOSED > UNDER_REVIEW > APPROVED > ACTIVE > DEPRECATED Subscription-based elevation is wired in for products via the existing `DataProductSubscriptionDb` table; contracts use ownership only (no subscription table today). 2. **Family-latest resolver endpoints** — `GET /api/data-contracts/families/{family_id}/latest` and the products counterpart. These resolve a family-follow-latest reference to a concrete row using the same role-aware rank, so any caller storing only a family id can read back the right version. 3. **EntityVersionPicker** — new shared component in `components/common/entity-version-picker.tsx`. Combobox over the collapsed list endpoint (one row per family with inline version badges), optional Entity-pinned / Family-follow-latest scope toggle, and an inline sub-picker for refining the version when pinning. The `link-contract-to-port-dialog` (closes #69) is migrated as the first call site, with `allowedScopes=['entity']` until the output-port reference-storage slice lands. Tests added: * `test_version_visibility.py` — 12 cases covering status visibility, rank ordering, tie-breaks, and the consumer-only / admin-only edges. * `test_version_family.py` — two new manager-level cases proving consumers see the active rep while team members of the same family see the in-flight draft. Note: the dev backend reloader has a pre-existing misconfiguration (noted in PR #447). Logic is covered by unit tests; live verification requires a manual `uvicorn` restart. * fix(versioning): camelCase API output + picker include_history fallback (#442 phase 3 follow-up) Two issues uncovered during Playwright smoke testing of #448: 1. **camelCase serialization on list endpoints.** The ``DataContractSummary`` and ``DataProduct`` Pydantic models declared their PRD-#442 fields (``versionFamilyId``, ``versionCount``, ``parentContractId/parentProductId``, ``baseName``, ``changeSummary``, ``draftOwnerId``) with snake_case ``alias``-es. FastAPI's default ``response_model_by_alias=True`` then emitted snake_case, but the FE TS types use camelCase — so ``row.versionCount`` was silently ``undefined`` and the count badge never rendered. Switch each field to use Pydantic v2's ``serialization_alias`` so the wire format is camelCase regardless of the by-alias toggle, while the existing snake_case ``alias`` keeps ORM ``from_attributes=True`` reading working for both the SQLAlchemy attribute and snake_case JSON input. 2. **Picker hid valid published versions inside elevated families.** With role-aware ranking landed in #448, a family whose newest row is a draft now collapses to that draft as its representative. The EntityVersionPicker only ever saw collapsed reps, so a port-link dialog scoped to ``statusFilter=['active','approved','certified']`` would silently drop families that had a perfectly valid published version available — e.g. Customer Data Contract disappeared from the POS Transaction Stream port picker after a 2.0.0 draft was created. When ``statusFilter`` is supplied, fetch with ``?include_history=true`` and collapse client-side after status filtering, preferring the newest matching version per family. ``versionCount`` is computed BEFORE collapse so the badge still reflects the full family size. Smoke-tested end-to-end via Playwright MCP against a multi-version family. Original v1.0.0 (active) is now selectable, picker write persists the entity-pinned contract id correctly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2 of the unified version family work (PRD #442). Makes the data-contracts and data-products list views collapse by
version_family_idby default, with a "Show all versions" toggle to expand. Each collapsed row gains a small "N versions" badge so users can see at a glance which entities have history.Stacked on #446 (Phase 1). Base branch is `feat-version-family` — please merge #446 first.
Backend
DataContractSummaryandDataProductAPI models addversionCount(aliasversion_count). Emitted only on the collapsed view so the expanded view never reports misleading per-row counts.DataContractsManager._query_contracts: drop the legacybase_namePython-side dedupe in favor of canonicalversion_family_idgrouping; return(rows, family_counts)so the builder attaches counts without a second query._build_contract_summariesnow also populatesparentContractId,versionFamilyId,baseName,changeSummary,draftOwnerIdon summary rows (these existed on the model but were always null in the response).list_contracts_from_db+/data-contractsroute propagateinclude_historyend-to-end.DataProductsManager.list_products: collapse byversion_family_idafter the visibility cascade, attachversion_countto the surviving row;include_history=Truebypasses the collapse and suppresses the count./data-productsroute surfacesinclude_history.Frontend
DataContractListItemandDataProductgainversionCount.components/common/version-count-badge.tsx— compact pill that hides itself for single-version families and otherwise renders a click-through history hint next to the version cell.data-contracts.tsxanddata-products.tsx: family badge next to the version column + "Show all versions" switch in the toolbar. Both list-fetch paths plumbinclude_historythrough the query string.Tests
include_historybypass on contracts, and product-side parity. Suite is now 17 → 22 passing.Test plan
test_version_family.py?domain_id=still respect the collapseNotes
--reload-dirpointing at the oldsrc/apilayout (visible in/tmp/backend.logas aFileNotFoundErrorfromstatreload). A backend restart is required to pick up the new wiring for live verification — unrelated to this PR.