LCOV - code coverage report
Current view: top level - dashql-app/src/views/query_result - result_table_overlay.tsx Coverage Total Hit
Test: DashQL 915828b Lines: 100.0 % 66 66
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as React from 'react';
       2              : import * as styles from './result_table_overlay.module.css';
       3              : 
       4              : import type { QueryExecutionState } from '../../query/query_execution_state.js';
       5              : import { ButtonSize, ButtonVariant, IconButton } from '../../ui/foundations/button.js';
       6              : import { useFocusTrap } from '../../ui/foundations/focus.js';
       7              : import { Overlay, OverlaySize } from '../../ui/foundations/overlay.js';
       8              : import { ScreenFullIcon, ScreenNormalIcon, SymbolIcon } from '../../ui/foundations/symbol_icon.js';
       9              : import { QueryResultDetails } from './query_result_details.js';
      10              : import { TableColumnHeader } from './data_table_cell.js';
      11              : 
      12              : export interface ResultTableOverlayDependencies {
      13              :     QueryResultDetails: typeof QueryResultDetails;
      14              : }
      15              : 
      16            1 : const DEFAULT_DEPENDENCIES: ResultTableOverlayDependencies = {
      17            1 :     QueryResultDetails,
      18            1 : };
      19              : 
      20              : interface Props {
      21              :     scriptName: string;
      22              :     query: QueryExecutionState;
      23              :     onClose: () => void;
      24              :     dependencies?: ResultTableOverlayDependencies;
      25              : }
      26              : 
      27              : /// The height of the card before it is enlarged, the table grows up to it and scrolls then
      28              : const MAX_CARD_HEIGHT = 600;
      29              : const HEADER_HEIGHT = 44;
      30              : // The table opens popups of its own (search, cell details), a click into them must not close the card
      31            1 : const IGNORE_OUTSIDE_CLICK = () => {};
      32            1 : const CloseIcon = SymbolIcon('x_16');
      33              : 
      34              : /// The full result table of a feed entry or a dashboard card in a card over the page: the table with its column plots
      35              : /// under a header with the name of the script, a button to enlarge the card to the window and a close button.
      36            1 : export function ResultTableOverlay(props: Props): React.ReactElement {
      37            1 :     const dependencies = props.dependencies ?? DEFAULT_DEPENDENCIES;
      38            1 :     const dialogRef = React.useRef<HTMLElement | null>(null);
      39            1 :     const [expanded, setExpanded] = React.useState(false);
      40              : 
      41              :     // Focus the dialog, not its first button
      42            1 :     useFocusTrap({
      43            1 :         containerRef: dialogRef as React.RefObject<HTMLElement>,
      44            1 :         initialFocusRef: dialogRef as React.RefObject<HTMLElement>,
      45            1 :         restoreFocusOnCleanUp: true,
      46            1 :     });
      47              : 
      48            1 :     return (
      49            1 :         <Overlay
      50            1 :             centered
      51            1 :             width={OverlaySize.XXL}
      52            1 :             height={OverlaySize.AUTO}
      53            1 :             maxHeight={OverlaySize.XL}
      54            1 :             preventFocusOnOpen
      55            1 :             expanded={expanded}
      56            1 :             onEscape={props.onClose}
      57            1 :             onClickOutside={IGNORE_OUTSIDE_CLICK}
      58              :         >
      59            1 :             <section
      60            1 :                 ref={dialogRef}
      61            1 :                 className={styles.dialog}
      62            1 :                 role="dialog"
      63            1 :                 aria-modal="true"
      64            1 :                 tabIndex={-1}
      65            1 :                 aria-label={`Query results of ${props.scriptName}`}
      66            1 :                 data-expanded={expanded || undefined}
      67            1 :                 data-testid="result-table-overlay"
      68              :             >
      69            1 :                 <header className={styles.header}>
      70            1 :                     <h2 className={styles.title}>{props.scriptName}</h2>
      71            1 :                     <div className={styles.spacer} />
      72            1 :                     <IconButton
      73            1 :                         variant={ButtonVariant.Invisible}
      74            1 :                         size={ButtonSize.Small}
      75            1 :                         aria-label={expanded ? 'Restore size' : 'Enlarge'}
      76            1 :                         aria-pressed={expanded}
      77            1 :                         data-testid="result-table-overlay-resize"
      78            1 :                         onClick={() => setExpanded(e => !e)}
      79              :                     >
      80            1 :                         {expanded ? <ScreenNormalIcon size={16} /> : <ScreenFullIcon size={16} />}
      81            1 :                     </IconButton>
      82            1 :                     <IconButton
      83            1 :                         variant={ButtonVariant.Invisible}
      84            1 :                         size={ButtonSize.Small}
      85            1 :                         aria-label="Close query results"
      86            1 :                         data-testid="result-table-overlay-close"
      87            1 :                         onClick={props.onClose}
      88              :                     >
      89            1 :                         <CloseIcon size={16} />
      90            1 :                     </IconButton>
      91            1 :                 </header>
      92            1 :                 <div className={styles.body}>
      93            1 :                     <dependencies.QueryResultDetails
      94            1 :                         query={props.query}
      95            1 :                         debugMode={false}
      96              :                         // The enlarged card fills the window, the table fills the card
      97            1 :                         fitHeight={!expanded}
      98            1 :                         maxHeight={expanded ? undefined : MAX_CARD_HEIGHT - HEADER_HEIGHT}
      99            1 :                         columnHeader={TableColumnHeader.WithColumnPlots}
     100            1 :                     />
     101            1 :                 </div>
     102            1 :             </section>
     103            1 :         </Overlay>
     104              :     );
     105            1 : }
        

Generated by: LCOV version 2.0-1