Skip to content

Add Dynamic View for unified cross-type mapping visualization#288

Merged
pellecchialuigi merged 10 commits into
mainfrom
dynamic-view
May 7, 2026
Merged

Add Dynamic View for unified cross-type mapping visualization#288
pellecchialuigi merged 10 commits into
mainfrom
dynamic-view

Conversation

@pellecchialuigi
Copy link
Copy Markdown
Collaborator

Introduce a new "Dynamic View" in the Mapping page that displays the full reference document alongside all directly mapped work items of every type in a unified two-column layout, providing a cross-type overview of specification coverage.

API - New dynamic-view endpoint:

  • Add ApiDynamicViewMapping resource at /mapping/api/dynamic-view
  • Returns the full specification text plus all direct work items (SW Requirements, Test Specifications, Test Cases, Justifications, Documents) grouped and deduplicated by work item ID
  • Each work item group carries a list of snippet mappings with section, offset, coverage, match flag, and relation_id
  • SW Requirement snippets include children (nested SRs, TSs, TCs) when the snippet matches the specification
  • Document snippets include nested Documents when matching
  • Add comprehensive unit tests in test_api_dynamic_view_mapping.py covering auth, error handling, response structure, deduplication, and children

Frontend - Dynamic View table component:

  • Add MappingDynamicViewTable component with two-column layout: reference document on the left, grouped work items on the right
  • Left column highlights covered sections in blue with a left border; uncovered sections appear in lighter color
  • Clicking a work item card selects it and narrows the reference document to show only the relevant mapped snippets
  • Add "Show full document" button to deselect and restore the full view
  • Show snippet count badge on each work item card
  • Support nested traceability: indirect Test Specifications, Test Cases, SW Requirements, and Documents rendered indented under their parent
  • Each card includes kebab menu, comments button, status label, version, and completion label

Frontend - Snippets management modal:

  • Add MappingSnippetsModal component for viewing, adding, and removing snippet mappings for a work item from the Dynamic View
  • "Manage Snippets" button available on each work item card for logged-in users with write permissions
  • Allows selecting text from the reference document to create new snippet mappings

Frontend - View selector and default view updates:

  • Add "Dynamic View" option to MappingViewSelect dropdown
  • Add _DV constant for 'dynamic-view'
  • Add "Justifications Only" and "Dynamic View" radio buttons to the API form default view settings
  • Update Mapping.tsx to fetch from the dynamic-view endpoint when selected and pass data to the new table component
  • Update MappingPageSection to conditionally render MappingDynamicViewTable vs MappingListingTable based on selected view

Frontend - Fix kebab menu click propagation in Dynamic View:

  • Add e.stopPropagation() to onToggleClick and onSelect in all 5 kebab menu components (SwRequirement, TestSpecification, TestCase, Justification, Document) to prevent the click from bubbling up to the parent Card and triggering the snippet selection behavior

Frontend - CSS color refinements:

  • Update .code-block-bg-green to #dbeafe (blue tint matching Dynamic View)
  • Update .code-block-bg-gold to #fef3c7
  • Update .code-block-bg-gray to #e5e7eb

Cypress E2E tests:

  • Add mapping_dynamic_view.cy.js with tests for switching to the Dynamic View, verifying mapped work items display, card selection/deselection, and multiple work item types rendering

Documentation:

  • Add mapping_views.rst describing all mapping views in detail
  • Add reference to the new doc in key_concepts.rst and index.rst

Refers to #286

Luigi Pellecchia added 10 commits April 29, 2026 16:12
Introduce a new "Dynamic View" in the Mapping page that displays the full
reference document alongside all directly mapped work items of every type in a
unified two-column layout, providing a cross-type overview of specification
coverage.

API - New dynamic-view endpoint:
- Add `ApiDynamicViewMapping` resource at `/mapping/api/dynamic-view`
- Returns the full specification text plus all direct work items (SW
  Requirements, Test Specifications, Test Cases, Justifications, Documents)
  grouped and deduplicated by work item ID
- Each work item group carries a list of snippet mappings with section, offset,
  coverage, match flag, and relation_id
- SW Requirement snippets include children (nested SRs, TSs, TCs) when the
  snippet matches the specification
- Document snippets include nested Documents when matching
- Add comprehensive unit tests in `test_api_dynamic_view_mapping.py` covering
  auth, error handling, response structure, deduplication, and children

Frontend - Dynamic View table component:
- Add `MappingDynamicViewTable` component with two-column layout: reference
  document on the left, grouped work items on the right
- Left column highlights covered sections in blue with a left border; uncovered
  sections appear in lighter color
- Clicking a work item card selects it and narrows the reference document to
  show only the relevant mapped snippets
- Add "Show full document" button to deselect and restore the full view
- Show snippet count badge on each work item card
- Support nested traceability: indirect Test Specifications, Test Cases, SW
  Requirements, and Documents rendered indented under their parent
- Each card includes kebab menu, comments button, status label, version, and
  completion label

Frontend - Snippets management modal:
- Add `MappingSnippetsModal` component for viewing, adding, and removing snippet
  mappings for a work item from the Dynamic View
- "Manage Snippets" button available on each work item card for logged-in users
  with write permissions
- Allows selecting text from the reference document to create new snippet
  mappings

Frontend - View selector and default view updates:
- Add "Dynamic View" option to `MappingViewSelect` dropdown
- Add `_DV` constant for `'dynamic-view'`
- Add "Justifications Only" and "Dynamic View" radio buttons to the API form
  default view settings
- Update `Mapping.tsx` to fetch from the dynamic-view endpoint when selected
  and pass data to the new table component
- Update `MappingPageSection` to conditionally render `MappingDynamicViewTable`
  vs `MappingListingTable` based on selected view

Frontend - Fix kebab menu click propagation in Dynamic View:
- Add `e.stopPropagation()` to `onToggleClick` and `onSelect` in all 5 kebab
  menu components (SwRequirement, TestSpecification, TestCase, Justification,
  Document) to prevent the click from bubbling up to the parent Card and
  triggering the snippet selection behavior

Frontend - CSS color refinements:
- Update `.code-block-bg-green` to `#dbeafe` (blue tint matching Dynamic View)
- Update `.code-block-bg-gold` to `#fef3c7`
- Update `.code-block-bg-gray` to `#e5e7eb`

Cypress E2E tests:
- Add `mapping_dynamic_view.cy.js` with tests for switching to the Dynamic
  View, verifying mapped work items display, card selection/deselection, and
  multiple work item types rendering

Documentation:
- Add `mapping_views.rst` describing all mapping views in detail
- Add reference to the new doc in `key_concepts.rst` and `index.rst`

Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
…yout

Replace the single-table layout in MappingDynamicViewTable with a split-panel
flex layout where the Reference Document and Work Items sections scroll
independently, and the page can scroll to dismiss the header controls while
keeping the section titles always visible.

Mapping.tsx:
- Disable sticky PageGroup behavior when Dynamic View is selected, allowing
  the page header (breadcrumb, view selector, indirect switches) to scroll
  away and give more vertical space to the content panels.

MappingDynamicViewTable.tsx:

Layout replacement (table → flex panels):
- Remove PatternFly Table/Thead/Tbody/Tr/Td/Th imports and PageSection wrapper
- Replace the single-row two-column table with a flex container (height: 100vh)
  where each side is an independently scrollable div (overflow-y: auto)
- Add sticky column headers ("REFERENCE DOCUMENT" / "WORK ITEMS") inside each
  panel that remain pinned at the top while the panel content scrolls

Scroll capping (prevent section titles from disappearing):
- Compute the maximum allowed scrollTop of the main content container so that
  the panels' top edge never scrolls above the viewport
- Intercept wheel events (passive: false) to prevent further scroll when at the
  maximum, and clamp scrollTop in the scroll handler as a fallback
- Lazy-compute maxScroll via requestAnimationFrame to ensure layout is stable

Work item selection scroll reset:
- When a work item is clicked (selected), scroll both panels (left and right)
  back to the top and reset the page scroll to 0, ensuring the section titles
  and selected item are immediately visible
- Add specPanelRef for the left (reference document) panel to enable this

Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
…ondition

Fix race condition in MappingSectionMenuKebab causing empty modalSection

The kebab dropdown menu computed snippetSection and snippetOffset inside a
useEffect that fires asynchronously after paint. When Cypress (or a fast user)
clicked a dropdown item before the effect propagated, the modal opened with an
empty modalSection, causing the form validation to silently reject the
submission and no work item to be created.

- Moved getSection()/getOffset() computation from useEffect into the
  onToggleClick handler so React batches the state updates into a single
  re-render, ensuring dropdown items always have the correct snippetSection
  from their first appearance
- Kept the useEffect only for the close case (resetting snippetOffset to -1)

Fix dynamic view Cypress tests for data conflicts and timing

Tests 3, 5, and 6 all reused sr_data.first to create a sw-requirement.
Since delete_work_item only removes the mapping (not the entity), subsequent
tests hit a 409 CONFLICT when trying to create the same sw-requirement again.

- Test 5 ("card selection highlights snippets") now uses sr_data.second
- Test 6 ("multiple work item types") now uses sr_data.third, including
  its title assertion
- Added cy.wait(const_data.long_wait) after every cy.delete_work_item() call
  to ensure backend cleanup completes before the next test runs
- Added scrollIntoView() and { force: true } on the "Show full document"
  button click, which was covered by the sticky navigation bar

Increase .find('.pf-v5-c-card') timeout in Cypress custom commands

The .find() calls in custom commands inherited Cypress's default 4s timeout
instead of the 15s timeout set on the parent cy.get(). After several
create/delete cycles the backend becomes slower, causing legitimate cards to
take longer to appear.

- Propagated { timeout: 15000 } to all .find('.pf-v5-c-card') calls in
  check_work_item, delete_work_item, assign_work_item,
  assign_existing_work_item, and edit_work_item
- Added tableOptions constant to delete_work_item, assign_work_item,
  assign_existing_work_item, and edit_work_item (was only in check_work_item)
- Removed leftover console.log debug statements from delete_work_item and
  edit_work_item

Prettier formatting pass

- Minor trailing comma and line-break formatting fixes applied by Prettier to
  cypress.config.ts, test_failing_tmt_test_case.cy.js,
  test_passing_tmt_test_case.cy.js, user_files.cy.js, commands.js, and
  TestRunConfigForm.tsx

New test file: mapping_nested_documents.cy.js

- Added e2e test for nested document mapping: creates a top-level document,
  edits it, maps a nested document under it, edits the nested document, then
  cleans up both in reverse order

Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
…lected text

Add the ability for users to select a snippet of the reference document
in the Dynamic View left panel and right-click to see which work items
are mapped to that specific text region. This enables quick navigation
from any part of the specification to its associated work items.

The matching is offset-aware, meaning it uses the character position of
the selected text within the specification string rather than a simple
string match. This correctly handles repeated substrings (e.g. "if" in a
C file) by only showing work items whose snippet offsets actually overlap
with the selected range.

- Add `specContentPreRef` ref and `contextMenu` state to track the
  custom right-click menu position and matching work items
- Add `handleSpecContextMenu` handler that computes the exact character
  offset range of the user's text selection within the specification
  using the DOM Range API, then finds all work item groups with snippets
  overlapping that range
- Each `<pre>` element in `renderSpecificationContent()` now carries a
  `data-spec-base-offset` attribute (0 for full document view, or
  `firstStart` when showing a focused subset for a selected work item)
  so the offset calculation is correct in all rendering modes
- Render a fixed-position context menu overlay showing matched work items
  grouped by type (SW Requirement, Test Specification, Test Case,
  Justification, Document) with their icon, id, and truncated title
- Clicking a context menu item selects the corresponding work item card,
  highlighting its snippets in the specification panel
- Context menu auto-dismisses on click outside, Escape key, or panel
  scroll to avoid stale menus
- Work item deduplication ensures each group appears at most once even if
  multiple snippets from the same work item overlap the selection
- Prettier formatting applied to TestRunConfigForm.tsx (cosmetic only)

Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
Sort the work items displayed in the right-click context menu of the
reference document panel so they appear in a predictable, easy-to-scan
order rather than the arbitrary order they happen to be found during
the snippet overlap search.

- Sort matching work items first by type (grouping all SW Requirements,
  Test Cases, etc. together) and then alphabetically by label within
  each type category
- Uses localeCompare for consistent locale-aware string ordering

Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
The local Prettier version (3.2.5) was formatting JSX differently from
the CI version (3.8.3), causing the pipeline prettier check to fail.
Upgrading the local version ensures consistent formatting across local
development and CI.

- Upgrade prettier from 3.2.5 to ^3.8.3 in app/package.json
- Re-run prettier on TestRunConfigForm.tsx to fix two formatting
  discrepancies where 3.2.5 collapsed multi-line JSX map callbacks
  into single lines, while 3.8.3 keeps them expanded across multiple
  lines (FormSelectOption inside sshKeys and testingFarmComposes maps)

Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
@pellecchialuigi pellecchialuigi marked this pull request as ready for review May 7, 2026 21:05
@pellecchialuigi pellecchialuigi merged commit b8ae531 into main May 7, 2026
4 checks passed
@pellecchialuigi pellecchialuigi deleted the dynamic-view branch May 7, 2026 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant