State Management
Relevant source files
The following files were used as context for generating this wiki page:The state management in Quant is designed to be entirely client-side, ensuring user privacy and full offline functionality. It leverages standard React hooks (useState, useEffect, useMemo, useCallback) for component-level state and the browser's localStorage API for persistence. This approach avoids the need for a backend server, as all calculations and data storage occur directly within the user's browser.
The architecture separates state into three primary domains: application-level UI state, real-time calculator state, and persistent score history. Communication between decoupled components, such as the calculator and the score manager, is handled through custom browser events.
Sources: src/components/FAQAccordion.tsx:31-47, src/components/CVSSCalculator.tsx, src/components/ScoreHistory.tsx
Core Principles
The state management strategy is built on the following principles:
- Client-Side Exclusivity: All application state, including vulnerability data and calculated scores, resides and is processed exclusively in the user's browser. No data is ever sent to an external server.
- Persistence via Local Storage: The browser's
localStorageis the persistence layer for user-generated content, such as saved scores in the Score Manager and user-specific UI settings. - Reactivity with React Hooks: The UI is built with React, and its state is managed reactively using a combination of
useStatefor direct state management,useMemofor expensive calculations and derived state, anduseEffectfor handling side effects like data fetching fromlocalStorageand score recalculations. - Decoupled Communication: Custom DOM events are used to signal state changes between independent components, promoting a decoupled architecture. For example, saving a new score dispatches an event that the Score Manager listens for to refresh its data.
Sources: src/components/FAQAccordion.tsx:34-37, src/components/ScoreHistory.tsx:440-444, src/components/CVSSCalculator.tsx:142-148
Local Storage Usage
The application uses localStorage to persist data across sessions.
| Key | Description | Managed By |
|---|---|---|
cvss_history | Stores an array of saved ScoreHistoryEntry objects for the Score Manager. | ScoreHistory.tsx |
cvss_calculator_settings | Stores user UI preferences, such as should_use_alternative_description and should_show_contributions. | CVSSCalculator.tsx |
Sources: src/components/ScoreHistory.tsx:28, 441, src/components/CVSSCalculator.tsx:32, 151
Application-Level State
The main CVSSCalculator component serves as the top-level state manager for the calculator interface. It handles global settings, URL parsing, and orchestrates the rendering of the correct calculator version.
Sources: src/components/CVSSCalculator.tsx
Key State Variables
| State Variable | Hook | Description |
|---|---|---|
activeTab | useState | Manages which CVSS version tab is currently active (e.g., "v4.0"). |
parsedVector | useState | Holds the parsed metrics from a CVSS vector string found in the URL on initial load. |
restoreVectorString | useState | A key used to force re-mounting of CVSSGenericCalculator when restoring a score. |
should_use_alternative_description | useState | A boolean flag for toggling between technical and simplified metric descriptions. Persisted in localStorage. |
should_show_contributions | useState | A boolean flag for showing the score impact of selecting a metric option. Persisted in localStorage. |
Sources: src/components/CVSSCalculator.tsx:19-70
Initialization and URL-based State
On initial load, the application's state is determined by parameters in the URL, allowing assessments to be shared via links.
The following diagram illustrates the initialization logic:
This flow ensures that a vector parameter takes precedence, providing a seamless experience when a user clicks a shared link. The component then cleans the URL, removing the vector parameter and replacing it with a version parameter for a cleaner user experience.
Sources: src/components/CVSSCalculator.tsx:73-95, src/components/CVSSCalculator.tsx:98-112
Cross-Component Event Handling
The CVSSCalculator listens for the cvss-restore-vector custom event, which is dispatched by the ScoreManager component. When a user clicks "Restore" on a saved score, this event is fired with the vector string in its detail payload. The CVSSCalculator captures this event, parses the vector, and updates its state to switch to the correct tab and pre-fill the metrics.
Sources: src/components/CVSSCalculator.tsx:115-131, src/components/ScoreHistory.tsx:516-529
Calculator State (CVSSGenericCalculator)
The CVSSGenericCalculator component is responsible for the state of a single CVSS version calculator. It manages the selected metrics and recalculates the score in real-time as the user makes changes.
Sources: src/components/CVSSGenericCalculator.tsx
Data Flow
The state management within the generic calculator follows a clear, reactive pattern.
This diagram shows the data flow when a user interacts with a metric:
- A user clicks a radio button for a metric option.
- The
updateMetriccallback is invoked, which callssetMetricsto update themetricsstate object. - The change in
metricstriggers auseEffecthook. - Inside the effect, the appropriate scoring function (e.g.,
calculateCVSSv4Score) is called with the new metrics. - The returned score and vector string are used to update the
scoreandvectorStringstates. - The UI, including the
ScoreCard, re-renders with the new values.
Sources: src/components/CVSSGenericCalculator.tsx:159-164, src/components/CVSSGenericCalculator.tsx:248-273
Initial State
The metrics state is initialized based on a priority order:
- If
initialMetricsare passed from a parsed URL vector, they are merged with the default metrics. - Otherwise, the component uses a set of default metrics defined for each CVSS version, which represent the least severe values.
Sources: src/components/CVSSGenericCalculator.tsx:128-138, src/lib/cvss/v2/scoring.ts:328-344, src/lib/cvss/v3/scoring.ts:515-538
Score History State (ScoreManager)
The ScoreManager component handles the state for all saved CVSS scores. It's a more complex stateful component that manages a list of scores, user selections, sorting, filtering, and dialog interactions.
Sources: src/components/ScoreHistory.tsx
State Structure and Persistence
The component's primary state is the history array, which holds ScoreHistoryEntry objects. This state is loaded from localStorage on component mount and is updated via CRUD functions.
The following sequence diagram illustrates how a score is saved and how the ScoreManager updates its view:
This event-driven mechanism allows the ScoreManager to update itself without being directly coupled to the calculator components.
Sources: src/components/ScoreHistory.tsx:427-438, src/components/ScoreHistory.tsx:450-457
Derived and Memoized State
To optimize performance, the ScoreManager heavily relies on the useMemo hook to derive state for filtering and sorting.
filteredHistory: This is derived from the mainhistorystate and thesearchstate. It is memoized to ensure the filter logic only runs when the history or search term changes.sortedHistory: This is derived fromfilteredHistoryand thesortstate. It is memoized to re-sort the list only when the data or sort criteria change, preventing unnecessary re-sorting on every render.
This pattern avoids costly computations on every re-render, ensuring the UI remains responsive even with a large number of saved scores.
Sources: src/components/ScoreHistory.tsx:460-470, src/components/ScoreHistory.tsx:473-504
Data Structures
The core data structures for state management are defined in types.ts.
CalculatorState: A generic interface representing the complete state of a calculator instance, including version, metrics, and the resulting score.ScoreHistoryEntry: Defines the shape of an object stored in thelocalStoragehistory array.
Sources: src/lib/cvss/types.ts:446-464, src/components/ScoreHistory.tsx:28-30