UI Consistency
21 requirements
·
43 scenarios
Workflow Menu Options
JR-ui-consistency-008
The workflow selector SHALL display all authorized workflows returned from the backend discovery endpoint.
- The menu SHALL include the built-in options
- The menu SHALL include each workflow returned by
- The menu SHALL include the built-in options
Autoselect (Default) and None- The menu SHALL include each workflow returned by
/api/v1/workflows
1 test scenario
- Authorized workflows appear in menu JR-ui-consistency-008.1
Theme Toggle Support
JR-ui-consistency-019
The application SHALL support light and dark themes with a user-accessible toggle.
- A theme toggle button SHALL be present in the sidebar footer
- Theme preference SHALL be persisted in localStorage
- The
- Default theme SHALL be "light"
- A theme toggle button SHALL be present in the sidebar footer
- Theme preference SHALL be persisted in localStorage
- The
data-theme attribute on document root SHALL reflect the current theme ("light" or "dark")- Default theme SHALL be "light"
2 test scenarios
- Theme toggle is accessible JR-ui-consistency-019.1
- Theme preference persists across sessions JR-ui-consistency-019.2
Host-Based Branding
JR-ui-consistency-021
The sidebar logo and alt text SHALL be determined by the deployment hostname, not hardcoded. White-label deployments (e.g.
- Logo source and alt text SHALL be resolved via a branding configuration that maps hostnames to brand assets
- The hostname matching SHALL support both exact match and subdomain matching (e.g.
- Unknown hostnames SHALL fall back to the default UseJunior branding
- The branding configuration SHALL be the single source of truth for logo paths — no hardcoded logo paths in components
- Adding a new white-label brand SHALL require only a configuration entry and a logo asset, not component changes
beta.homeincentiveshub.com) SHALL display their own logo instead of the default UseJunior logo.- Logo source and alt text SHALL be resolved via a branding configuration that maps hostnames to brand assets
- The hostname matching SHALL support both exact match and subdomain matching (e.g.
homeincentiveshub.com matches beta.homeincentiveshub.com)- Unknown hostnames SHALL fall back to the default UseJunior branding
- The branding configuration SHALL be the single source of truth for logo paths — no hardcoded logo paths in components
- Adding a new white-label brand SHALL require only a configuration entry and a logo asset, not component changes
4 test scenarios
- White-label deployment shows custom logo JR-ui-consistency-021.1
- Default deployment shows UseJunior logo JR-ui-consistency-021.2
- Unknown hostname falls back to default JR-ui-consistency-021.3
- Subdomain matching works JR-ui-consistency-021.4
Chat State Persistence
JR-ui-consistency-033
Chat conversations, messages, and the active conversation SHALL be persisted with backend sync when chat persistence is enabled, and SHALL fall back to localStorage as a cache and offline bootstrap.
- The chat state (
- For domains with backend chat persistence enabled, the backend SHALL be the source of truth on startup
- On page load, localStorage MAY be used immediately for fast render, then reconciled with backend data (backend wins conflicts)
- Messages SHALL be limited to 100 per conversation to prevent localStorage overflow (~5MB limit)
- Transient state (processingChatIds, progressState, pendingContexts) SHALL NOT be persisted
- Invalid or missing stored values SHALL default to an empty state with no conversations
- Processing status SHALL be reset to
- Rationale: Users expect to return to their conversation after a page refresh; losing chat history is disruptive
- The chat state (
conversations, messages, activeConversationId) SHALL be stored in localStorage under the key chatState as a cache- For domains with backend chat persistence enabled, the backend SHALL be the source of truth on startup
- On page load, localStorage MAY be used immediately for fast render, then reconciled with backend data (backend wins conflicts)
- Messages SHALL be limited to 100 per conversation to prevent localStorage overflow (~5MB limit)
- Transient state (processingChatIds, progressState, pendingContexts) SHALL NOT be persisted
- Invalid or missing stored values SHALL default to an empty state with no conversations
- Processing status SHALL be reset to
'idle' on restore (to prevent stuck "processing" states)- Rationale: Users expect to return to their conversation after a page refresh; losing chat history is disruptive
6 test scenarios
- Active conversation persists after page refresh JR-ui-consistency-033.1
- Backend is source of truth for persistence-enabled domains JR-ui-consistency-033.2
- Chat messages persist after page refresh JR-ui-consistency-033.3
- Multiple conversations persist JR-ui-consistency-033.4
- Empty state when no stored data JR-ui-consistency-033.5
- Transient state is not persisted JR-ui-consistency-033.6
Confirmation Modal Component
JR-ui-consistency-035
The application SHALL provide a reusable ConfirmationModal component for confirming destructive or significant actions.
- ConfirmationModal SHALL use the HTML
- ConfirmationModal SHALL support customizable title, message, and button text
- ConfirmationModal SHALL support a
- ConfirmationModal SHALL support an
- ConfirmationModal message SHALL support HTML content via
- ConfirmationModal SHALL close on backdrop click and Escape key
- ConfirmationModal SHALL be managed via uiStore state, not window globals
- ConfirmationModal SHALL use the HTML
<dialog> element for native modal behavior- ConfirmationModal SHALL support customizable title, message, and button text
- ConfirmationModal SHALL support a
confirmVariant prop for styling (primary or danger)- ConfirmationModal SHALL support an
isLoading prop to show processing state- ConfirmationModal message SHALL support HTML content via
dangerouslySetInnerHTML- ConfirmationModal SHALL close on backdrop click and Escape key
- ConfirmationModal SHALL be managed via uiStore state, not window globals
2 test scenarios
- Delete confirmation modal appears JR-ui-consistency-035.1
- Confirmation modal closes on backdrop click JR-ui-consistency-035.2
Context Attachment Modals
JR-ui-consistency-038
The chat interface SHALL provide modals for attaching context (contracts, deals, property profiles) to conversations.
- ContractGridModal SHALL fetch and display available contract sets from the API
- ContractGridModal SHALL show set name, contract count, and prompt count
- DealContextModal SHALL fetch and display available deals from the API
- PropertyContextModal SHALL allow creating, editing, and selecting property profiles
- Selecting an item in any context modal SHALL add it to pending attachments
- Context modals SHALL be managed via uiStore state
- ContractGridModal SHALL fetch and display available contract sets from the API
- ContractGridModal SHALL show set name, contract count, and prompt count
- DealContextModal SHALL fetch and display available deals from the API
- PropertyContextModal SHALL allow creating, editing, and selecting property profiles
- Selecting an item in any context modal SHALL add it to pending attachments
- Context modals SHALL be managed via uiStore state
1 test scenario
- Attach contract grid to chat JR-ui-consistency-038.1
Citation Modal for Contract Analysis
JR-ui-consistency-039
The contract analysis view SHALL provide a modal for viewing paragraph citations in context.
- CitationModal SHALL display the full paragraph text from the contract
- CitationModal SHALL highlight the cited section if applicable
- CitationModal state SHALL be managed in the contract analysis store
- Clicking a citation link in the grid SHALL open the CitationModal
- CitationModal SHALL display the full paragraph text from the contract
- CitationModal SHALL highlight the cited section if applicable
- CitationModal state SHALL be managed in the contract analysis store
- Clicking a citation link in the grid SHALL open the CitationModal
1 test scenario
- View citation in modal JR-ui-consistency-039.1
Suggested Edit Loading Shimmer
JR-ui-consistency-040
The "Suggested Edits" column in the Review Workbench SHALL display a shimmer/pulse loading animation while edits are being generated.
- When a row's suggested edit is pending generation, the cell SHALL show an animated shimmer effect
- The shimmer SHALL replace the static em-dash (—) during loading
- The shimmer animation SHALL use
- The shimmer SHALL display descriptive text like "Generating..." alongside the animation
- Loading state SHALL be derived from:
- Static em-dash (—) SHALL only appear when processing is complete with no suggested edit
- Rationale: Animated loading indicators communicate active processing, reducing user uncertainty
- When a row's suggested edit is pending generation, the cell SHALL show an animated shimmer effect
- The shimmer SHALL replace the static em-dash (—) during loading
- The shimmer animation SHALL use
animate-pulse or equivalent CSS animation- The shimmer SHALL display descriptive text like "Generating..." alongside the animation
- Loading state SHALL be derived from:
isPending prop OR (no opcodes AND review status is processing)- Static em-dash (—) SHALL only appear when processing is complete with no suggested edit
- Rationale: Animated loading indicators communicate active processing, reducing user uncertainty
3 test scenarios
- Shimmer displays during edit generation JR-ui-consistency-040.1
- Shimmer clears on completion JR-ui-consistency-040.2
- Static empty state when no shimmer needed JR-ui-consistency-040.3
Tenant-Configurable Sidebar Labels and Visibility
JR-ui-consistency-044
The sidebar SHALL support host-based configuration for section labels and visibility so tenant deployments can hide or rename sections.
2 test scenarios
- Tenant hides Playbooks and Reviews JR-ui-consistency-044.1
- Tenant renames chat section label JR-ui-consistency-044.2
Tenant-Filtered Workflow Selector
JR-ui-consistency-045
The workflow selector SHALL filter available workflows based on tenant configuration.
2 test scenarios
- Tenant allowlist filters workflows JR-ui-consistency-045.1
- Tenant priority influences workflow order JR-ui-consistency-045.2
Contract Analysis Action Loading Feedback
JR-ui-consistency-047
Contract analysis actions that trigger long-running backend work SHALL show visible loading feedback and disable repeat actions while pending.
- Actions include sync, import, add column, delete column, delete contract, and regeneration
- While a mutation is pending, the initiating control SHALL display a spinner or in-progress label
- Related controls SHALL be disabled to prevent duplicate requests
- Loading feedback SHALL clear on both success and error
- Actions include sync, import, add column, delete column, delete contract, and regeneration
- While a mutation is pending, the initiating control SHALL display a spinner or in-progress label
- Related controls SHALL be disabled to prevent duplicate requests
- Loading feedback SHALL clear on both success and error
1 test scenario
- Grid sync shows loading state JR-ui-consistency-047.1
Playbook Upload Loading Feedback
JR-ui-consistency-049
Playbook upload interactions SHALL display a visible loading indicator while the upload request or subsequent playbook list refetch is in progress.
- The Upload action SHALL show a spinner or inline loading indicator while the upload mutation is pending
- The playbook selector panel SHALL treat "loading" as true when either the upload mutation is pending OR the playbooks query is fetching
- Loading feedback SHALL clear on both success and error
- The Upload action SHALL show a spinner or inline loading indicator while the upload mutation is pending
- The playbook selector panel SHALL treat "loading" as true when either the upload mutation is pending OR the playbooks query is fetching
- Loading feedback SHALL clear on both success and error
3 test scenarios
- Upload shows spinner during request JR-ui-consistency-049.1
- Selector panel shows loading during refetch JR-ui-consistency-049.2
- Loading clears on error JR-ui-consistency-049.3
Grid Review Manual Grid Creation
JR-ui-consistency-050
The Grid Review feature SHALL provide a "New Grid" button that allows users to create an empty grid without importing from a shared folder.
- The "New Grid" button SHALL be visible in the GridSelectorPanel regardless of whether grids already exist
- Clicking "New Grid" SHALL prompt the user for a grid name
- After entering a valid name, the system SHALL call
- After successful creation, the view SHALL navigate into the newly created grid
- If the user cancels the name prompt or enters an empty name, no grid SHALL be created
- The "New Grid" button SHALL be visible in the GridSelectorPanel regardless of whether grids already exist
- Clicking "New Grid" SHALL prompt the user for a grid name
- After entering a valid name, the system SHALL call
POST /api/v1/contracts/sets to create the grid- After successful creation, the view SHALL navigate into the newly created grid
- If the user cancels the name prompt or enters an empty name, no grid SHALL be created
2 test scenarios
- User creates a new empty grid JR-ui-consistency-050.1
- User cancels new grid creation JR-ui-consistency-050.2
Grid Review Folder Import Uses Sync Endpoint
JR-ui-consistency-051
When a user imports a shared folder in the Grid Review, the system SHALL use the folder sync endpoint (
- The import handler SHALL NOT use the file import endpoint (
- The sync endpoint auto-detects Google Drive vs SharePoint from the URL, so no
- After a successful folder sync, the grid list SHALL be refreshed and the user returned to the grid selector
POST /api/v1/contracts/folders/sync) which auto-creates a grid from the folder contents.- The import handler SHALL NOT use the file import endpoint (
POST /api/v1/contracts/files/import) for folder-level imports- The sync endpoint auto-detects Google Drive vs SharePoint from the URL, so no
source parameter SHALL be hardcoded- After a successful folder sync, the grid list SHALL be refreshed and the user returned to the grid selector
2 test scenarios
- User imports a Google Drive folder JR-ui-consistency-051.1
- User imports a SharePoint folder JR-ui-consistency-051.2
Chat Context Persistence in Conversation
JR-ui-consistency-053
Chat context attachments SHALL remain visible and active across follow-up messages until the user removes them.
2 test scenarios
- Context cards remain after sending JR-ui-consistency-053.1
- Contexts are removable by the user JR-ui-consistency-053.2
User Message Attachment Summary
JR-ui-consistency-054
User messages that include uploaded files SHALL display an attachment summary in the chat history.
2 test scenarios
- User message lists attached file names JR-ui-consistency-054.1
- Message without attachments omits summary JR-ui-consistency-054.2
Output Attachment Download Links
JR-ui-consistency-055
Assistant messages with output attachments SHALL provide working download links using the token-based download endpoint.
2 test scenarios
- Output attachments expose download link JR-ui-consistency-055.1
- Download link triggers file retrieval JR-ui-consistency-055.2
Review Workbench Apply State Sync
JR-ui-consistency-056
When review edits are applied, the workbench UI SHALL immediately reflect applied status so users can navigate edits and download revised documents.
- Applied rows SHALL render the applied state (check icon + edit/bookmark links) instead of Apply/Ignore buttons.
- When there are zero open edits, "Apply All" and "Apply All + Comments" SHALL be disabled and non-interactive.
- After one or more edits are applied, the "Download Revised" action SHALL be enabled.
- Applied rows SHALL render the applied state (check icon + edit/bookmark links) instead of Apply/Ignore buttons.
- When there are zero open edits, "Apply All" and "Apply All + Comments" SHALL be disabled and non-interactive.
- After one or more edits are applied, the "Download Revised" action SHALL be enabled.
2 test scenarios
- Apply-all completion hides row action buttons JR-ui-consistency-056.1
- Download Revised enables after edits apply JR-ui-consistency-056.2
Edited Recommended Response Indicator
JR-ui-consistency-059
When a user edits the Recommended Response, the response cell SHALL display the edited text with an explicit "(edited)" indicator.
- The "(edited)" indicator SHALL appear immediately after the edited response text
- The edited response text SHALL reflect the user-provided content, not the pre-edit suggestion
- The indicator SHALL be styled consistently with other edited markers in the review table
- Rationale: Users must see which responses have been manually modified before applying edits
- The "(edited)" indicator SHALL appear immediately after the edited response text
- The edited response text SHALL reflect the user-provided content, not the pre-edit suggestion
- The indicator SHALL be styled consistently with other edited markers in the review table
- Rationale: Users must see which responses have been manually modified before applying edits
1 test scenario
- Edited response shows edited indicator JR-ui-consistency-059.1
Genealogy Shows User-Edited Provenance
JR-ui-consistency-060
When a user edits the Recommended Response and then applies the edit, the edit genealogy SHALL display provenance indicating the response was user-edited.
- Genealogy SHALL include a provenance label such as "User Edited" or "User Modified"
- The provenance label SHALL appear alongside other source metadata in the genealogy popover
- This applies to edits generated from revised recommended responses as well as original AI responses
- Genealogy SHALL include a provenance label such as "User Edited" or "User Modified"
- The provenance label SHALL appear alongside other source metadata in the genealogy popover
- This applies to edits generated from revised recommended responses as well as original AI responses
1 test scenario
- Genealogy indicates user-edited response JR-ui-consistency-060.1
Genealogy Consistency for Apply vs Apply All
JR-ui-consistency-061
Edit genealogy SHALL render consistently regardless of whether edits are applied via "Apply" (single row) or "Apply All".
- Single-row Apply SHALL populate genealogy data in the same shape as Apply All
- The genealogy popover SHALL display the same sections and metadata for both flows
- The user SHALL NOT experience missing genealogy details when applying a single row
- Single-row Apply SHALL populate genealogy data in the same shape as Apply All
- The genealogy popover SHALL display the same sections and metadata for both flows
- The user SHALL NOT experience missing genealogy details when applying a single row
1 test scenario
- Single-row Apply shows full genealogy JR-ui-consistency-061.1