-
Notifications
You must be signed in to change notification settings - Fork 0
MDS UI State Management
- Introduction
- MDS State Object Structure
- Sorting Implementation
- Column Width Management
- Horizontal Scrolling Synchronization
- UI State Persistence
- Window Resizing Handling
- Integration with Data Loading and Filtering
- Conclusion
The MDS (Metadata Service) UI state management system is responsible for maintaining the current state of the MDS overlay, which displays information about FIDO authenticators. This system manages various aspects of the user interface including sorting, filtering, layout preferences, and state persistence across page reloads. The core of this system is the mdsState object, which serves as the central repository for all UI state information. The system is designed to provide a responsive and consistent user experience by efficiently managing data presentation, handling user interactions, and preserving user preferences.
Section sources
- mds.js
The mdsState object is the central component of the MDS UI state management system, storing all relevant state information for the MDS overlay. This object is initialized during the document's DOMContentLoaded event and contains various properties that track the current UI state.
The mdsState object includes properties for managing filters, sorting, table layout, and UI components. It maintains references to DOM elements such as the table container, filter inputs, sort buttons, and various UI controls. The state object also tracks metadata about the loaded data, including snapshot information and loading status.
Key properties of the mdsState object include:
-
filters: An object containing the current filter values for each filterable column -
sort: An object containing the current sort key and direction -
tableContainer: Reference to the main table container element -
horizontalScrollContainer: Reference to the horizontal scroll container element -
columnWidths: Array storing the current width of each column -
byAaguid: A Map object that indexes entries by their AAGUID for quick lookup
The state object also maintains references to various UI components such as the custom metadata panel, update overlay, certificate page, and authenticator modal, allowing for coordinated state management across different parts of the interface.
classDiagram
class MdsState {
+Object filters
+Object sort
+HTMLElement tableContainer
+HTMLElement table
+HTMLElement tableBody
+HTMLElement horizontalScrollContainer
+HTMLElement horizontalScrollContent
+Map sortButtons
+HTMLElement countEl
+HTMLElement totalEl
+HTMLElement statusEl
+Array columnWidths
+Array columnMinWidths
+Array columnResizers
+Object updateButton
+HTMLElement updateOverlay
+HTMLElement updateOverlayMessage
+HTMLElement updateOverlayCancel
+HTMLElement certificatePage
+HTMLElement certificateHeader
+HTMLElement certificatePageBody
+HTMLElement certificateSummary
+HTMLElement certificateClose
+HTMLElement authenticatorModal
+HTMLElement authenticatorHeader
+Object activeDetailEntry
+HTMLElement highlightedRow
+String highlightedRowKey
+Map byAaguid
+HTMLElement scrollTopButton
+Boolean scrollTopButtonVisible
}
**Diagram sources **
- mds.js
- mds.js
Section sources
- mds.js
- mds.js
The MDS UI implements a comprehensive sorting system that allows users to sort the metadata table by different columns. The sorting functionality is built around three distinct sort states: SORT_NONE, SORT_ASCENDING, and SORT_DESCENDING.
The sorting constants are defined as:
-
SORT_NONE = 'none': No sorting applied -
SORT_ASCENDING = 'asc': Ascending order sorting -
SORT_DESCENDING = 'desc': Descending order sorting
These states are managed through the SORT_SEQUENCE object, which defines the transition between sort states when a user clicks on a sort button. By default, clicking a previously unsorted column applies ascending sort, subsequent clicks toggle between descending sort and no sorting.
stateDiagram-v2
[*] --> SORT_NONE
SORT_NONE --> SORT_ASCENDING : Click on sort button
SORT_ASCENDING --> SORT_DESCENDING : Click on sort button
SORT_DESCENDING --> SORT_NONE : Click on sort button
**Diagram sources **
- mds.js
The system supports sorting by multiple columns through the SORT_ACCESSORS object, which defines how to extract sort values from data entries for each sortable column. These accessors handle various data types including strings, dates, and numeric values, ensuring proper sorting behavior.
When a user clicks on a sort button, the handleSortButtonClick function is triggered, which updates the sort state in the mdsState object and reapplies the filters to refresh the table with the new sort order. The applySorting function then processes the data entries according to the current sort criteria, using the appropriate accessor function to extract sort values and comparing them appropriately.
The system also includes special handling for the default sort column (dateUpdated), which has a different sort sequence defined in SORT_SEQUENCE_OVERRIDES to ensure it defaults to descending order (newest items first).
Section sources
- mds.js
- mds.js
- mds.js
- mds.js
The MDS UI implements a sophisticated column width management system that allows users to resize columns and preserves these preferences across sessions. The system tracks column widths through the columnWidths array in the mdsState object, which stores the width of each column in pixels.
Column width initialization occurs in the stabiliseColumnWidths function, which measures the natural width of header cells and establishes minimum widths for each column. This function is called during table rendering to ensure columns are properly sized based on their content.
flowchart TD
A[Initialize Column Widths] --> B[Measure Header Cell Widths]
B --> C{Widths Valid?}
C --> |Yes| D[Store in mdsState.columnWidths]
C --> |No| E[Retry with Animation Frame]
D --> F[Apply Widths to All Cells]
F --> G[Update Resizer Metrics]
**Diagram sources **
- mds.js
The system uses the applyColumnWidths function to apply the stored widths to all table cells, ensuring consistent column sizing across header and data rows. This function sets explicit width, minWidth, and maxWidth CSS properties on each cell to prevent unwanted resizing.
Column resizing is handled through dedicated resizer elements that users can drag to adjust column widths. The system tracks resizer state through properties like columnResizers, columnResizeState, and columnResizersEnabled in the mdsState object. When a user resizes a column, the system updates the corresponding entry in the columnWidths array and reapplies the widths to all cells.
The normaliseColumnWidths function ensures that all column widths meet the minimum requirement defined by DEFAULT_MIN_COLUMN_WIDTH (64 pixels), preventing columns from becoming too narrow and unreadable.
Section sources
- mds.js
- mds.js
- mds.js
- mds.js
The MDS UI implements a synchronized horizontal scrolling system that provides a floating scroll bar at the bottom of the viewport for better usability on large tables. This system ensures that scrolling in the main table container is mirrored in the floating scroll container and vice versa.
The synchronization is managed through the syncHorizontalScrollPositions function, which copies the scrollLeft value from one container to the other while preventing recursive calls through the isSyncingHorizontalScroll flag.
sequenceDiagram
participant User
participant MainTable as Table Container
participant FloatingScroll as Horizontal Scroll Container
User->>MainTable : Scroll horizontally
MainTable->>FloatingScroll : syncHorizontalScrollPositions()
FloatingScroll->>FloatingScroll : Update scrollLeft
FloatingScroll->>MainTable : syncHorizontalScrollPositions()
MainTable->>MainTable : Update scrollLeft (no change)
User->>FloatingScroll : Scroll horizontally
FloatingScroll->>MainTable : syncHorizontalScrollPositions()
MainTable->>MainTable : Update scrollLeft
MainTable->>FloatingScroll : syncHorizontalScrollPositions()
FloatingScroll->>FloatingScroll : Update scrollLeft (no change)
**Diagram sources **
- mds.js
The system uses several scheduled update functions to maintain the floating scroll bar's position and visibility:
-
scheduleHorizontalScrollMetricsUpdate: Updates the metrics and positioning of the floating scroll bar -
updateHorizontalScrollMetrics: Calculates whether the table overflows horizontally and updates the floating scroll bar accordingly -
updateFloatingHorizontalScrollPosition: Adjusts the floating scroll bar's position to remain visible at the bottom of the viewport
The floating scroll bar is only displayed when the table content exceeds the container width, as determined by comparing tableWidth and containerWidth in the updateHorizontalScrollMetrics function. When visible, the floating scroll bar is positioned with margins defined by FLOATING_SCROLL_SIDE_MARGIN (16px) and FLOATING_SCROLL_BOTTOM_MARGIN (24px) to ensure it doesn't overlap with other UI elements.
Section sources
- mds.js
- mds.js
- mds.js
- mds.js
The MDS UI system implements state persistence to maintain user preferences across page reloads. This is achieved through a combination of server-provided initial state and client-side caching mechanisms.
When the page loads, the system first attempts to apply metadata from server-provided initial state (stored in window.__INITIAL_MDS_JWS__ and window.__INITIAL_MDS_INFO__). If this is not available, it tries to restore from a cached state using the readMetadataCache function. Currently, the storeMetadataCache and readMetadataCache functions are implemented as no-ops, indicating that persistent caching is disabled, but the infrastructure is in place for future implementation.
flowchart TD
A[Page Load] --> B{Initial MDS JWS Available?}
B --> |Yes| C[Apply Initial Metadata Payload]
B --> |No| D{Cached Metadata Available?}
D --> |Yes| E[Restore from Cache]
D --> |No| F[Load from Network]
C --> G[Store in Cache]
E --> G
F --> G
G --> H[Initialize UI]
**Diagram sources **
- mds.js
- mds.js
The system preserves several aspects of UI state:
- Filter values in the
filtersobject - Sort state in the
sortobject - Column widths in the
columnWidthsarray - Custom metadata entries in the
customMetadataItemsarray
When metadata is loaded or refreshed, the system stores the enhanced metadata (including custom entries) in the cache using storeMetadataCache, along with metadata about the source and timestamp. This allows for quick restoration of the complete state on subsequent visits.
The clearMetadataCache function is provided to reset the cache when necessary, such as when custom metadata is deleted or when a full reload is requested.
Section sources
- mds.js
- mds.js
- mds.js
- mds.js
The MDS UI system includes comprehensive handling of window resizing events to maintain optimal layout and performance. The system listens for both 'scroll' and 'resize' events on the window object and responds by scheduling updates to various UI components.
flowchart TD
A[Window Event] --> B{Event Type}
B --> |scroll| C[handleWindowScroll]
B --> |resize| C[handleWindowScroll]
C --> D[scheduleScrollTopButtonUpdate]
C --> E[scheduleColumnResizerMetricsUpdate]
C --> F[scheduleHorizontalScrollMetricsUpdate]
D --> G[updateScrollTopButtonVisibility]
E --> H[updateColumnResizerMetrics]
F --> I[updateHorizontalScrollMetrics]
**Diagram sources **
- mds.js
- mds.js
The handleWindowScroll function is triggered by both scroll and resize events and schedules updates to three key UI components:
- Scroll top button visibility
- Column resizer metrics (height)
- Horizontal scroll metrics (position and visibility)
Each of these updates is scheduled using requestAnimationFrame or setTimeout to prevent excessive reflows and maintain performance during continuous events like scrolling or resizing.
The system also handles tab changes through the 'tab:changed' event listener, which hides or shows UI elements like the scroll top button and horizontal scroll bar depending on whether the MDS tab is active.
Additionally, the system includes a waitForLayoutSettled function that uses double requestAnimationFrame calls to ensure the layout has stabilized before performing operations that depend on accurate element dimensions, such as row height locking and column width stabilization.
Section sources
- mds.js
- mds.js
- mds.js
The MDS UI state management system is tightly integrated with the data loading and filtering systems to provide a cohesive user experience. The system uses a lazy loading approach for large datasets, initially loading only essential fields and progressively enhancing entries with additional details in the background.
When data is loaded through the loadMdsData function, it passes through several processing stages:
- Initial metadata is fetched from the server
- Custom metadata entries are merged using
ensureCustomMetadata - Entries are transformed using
transformEntryortransformEntryLightweight - Filter and sort state is applied
- UI components are updated
flowchart TD
A[Load Data] --> B[Fetch Metadata]
B --> C[Merge Custom Metadata]
C --> D{Large Dataset?}
D --> |Yes| E[Apply Lightweight Transform]
D --> |No| F[Apply Full Transform]
E --> G[Start Background Processing]
F --> H[Process Certificate Info]
G --> I[Update UI with Initial Data]
H --> I
I --> J[Apply Filters and Sorting]
J --> K[Render Table]
**Diagram sources **
- mds.js
- mds.js
The filtering system works in conjunction with the current state by using the filters object in mdsState to determine which entries should be displayed. The applyFilters function processes the full dataset through the matchesFilters function, which checks each entry against the current filter values for all columns.
The sorting system integrates with filtering by applying the current sort criteria to the filtered dataset before rendering. This ensures that users see sorted results within their current filter context.
The system also handles dynamic updates to the data, such as when custom metadata is uploaded or deleted. In these cases, the refreshCustomMetadataAfterUpload function reloads the data while preserving the current UI state, providing a seamless experience.
Section sources
- mds.js
- mds.js
- mds.js
- mds.js
The MDS UI state management system provides a comprehensive solution for maintaining the state of the MDS overlay, offering robust features for sorting, filtering, layout management, and state persistence. The system is centered around the mdsState object, which serves as a single source of truth for all UI state information.
Key strengths of the system include:
- Support for three sort states (none, ascending, descending) with configurable sort sequences
- Flexible column width management with user-resizable columns
- Synchronized horizontal scrolling with a floating scroll bar for improved usability
- State persistence across page reloads through caching mechanisms
- Responsive handling of window resizing and layout changes
- Tight integration with data loading and filtering systems
The system demonstrates a thoughtful approach to state management, balancing immediate user feedback with background processing for large datasets. By separating concerns and using scheduled updates, the system maintains performance while providing a rich, interactive user experience.
Future enhancements could include implementing persistent client-side storage for user preferences, expanding the range of sortable columns, and adding more sophisticated layout options for different screen sizes.
Section sources
- mds.js
- mds.js
- mds.js
- mds.js
- mds.js
- mds.js
- mds.js