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

            Line data    Source code
       1              : import * as React from 'react';
       2              : import { ConnectionHealth, type ConnectionState } from '../connections/connection_state.js';
       3              : import { Tooltip } from '../ui/foundations/tooltip.js';
       4              : 
       5              : export const CONNECTION_ATTENTION_DURATION_MS = 900;
       6              : 
       7              : interface ConnectionAttention {
       8              :     sessionId: string | null;
       9              :     active: boolean;
      10              :     request: (sessionId: string) => void;
      11              : }
      12              : 
      13            1 : export const SessionConnectionAttentionContext = React.createContext<ConnectionAttention | null>(null);
      14              : 
      15              : /// The connections whose health resets the attention, as a key that changes with them
      16            1 : export function connectionHealthKey(connections: readonly ConnectionState[] | null): string {
      17            1 :     return (connections ?? []).map(connection => `${connection.connectionId}:${connection.connectionHealth}`).join(',');
      18            1 : }
      19              : 
      20              : /// The connections of a session that are not online, a session runs once they are
      21            1 : export function connectionsToConnect(connections: Iterable<ConnectionState>): ConnectionState[] {
      22            1 :     return [...connections].filter(connection => connection.connectionHealth !== ConnectionHealth.ONLINE);
      23            1 : }
      24              : 
      25            1 : export function useSessionConnectionAttention(sessionId: string | null, healthKey: string): ConnectionAttention {
      26            1 :     const shared = React.useContext(SessionConnectionAttentionContext);
      27            1 :     const [active, setActive] = React.useState(false);
      28            1 :     const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null);
      29            1 :     React.useLayoutEffect(() => {
      30            1 :         setActive(false);
      31            1 :         if (timer.current != null) clearTimeout(timer.current);
      32            1 :         timer.current = null;
      33            1 :         return () => {
      34            1 :             if (timer.current != null) clearTimeout(timer.current);
      35            1 :             timer.current = null;
      36            1 :         };
      37            1 :     }, [sessionId, healthKey]);
      38              :     // Callers request attention for the connections the scripts of the session run on
      39            1 :     const request = React.useCallback((targetSessionId: string) => {
      40            1 :         if (targetSessionId !== sessionId || timer.current != null) return;
      41            1 :         setActive(true);
      42            1 :         timer.current = setTimeout(() => {
      43            1 :             timer.current = null;
      44            1 :             setActive(false);
      45            1 :         }, CONNECTION_ATTENTION_DURATION_MS);
      46            1 :     }, [sessionId]);
      47              :     // The value is provided as context to every execute button in the feed, keep it stable
      48            1 :     const own = React.useMemo(() => ({ sessionId, active, request }), [sessionId, active, request]);
      49            1 :     return shared?.sessionId === sessionId ? shared : own;
      50            1 : }
      51              : 
      52            1 : export function ExecuteConnectionGuard(props: { sessionId: string; blocked: boolean; children: React.ReactElement }) {
      53            1 :     const attention = React.useContext(SessionConnectionAttentionContext);
      54            1 :     return <Tooltip type="description" direction="s" text={props.blocked ? 'Connect to execute queries' : 'Query execution control'}>
      55            1 :         <span data-execution-connection-blocked={props.blocked ? 'true' : undefined}
      56            1 :             style={{ display: 'inline-flex' }} tabIndex={props.blocked ? 0 : undefined}
      57            1 :             onPointerOverCapture={event => {
      58            1 :                 if (props.blocked && !(event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget))) {
      59            1 :                     attention?.request(props.sessionId);
      60              :                 }
      61            1 :             }}>
      62            1 :             {props.children}
      63            1 :         </span>
      64            1 :     </Tooltip>;
      65            1 : }
        

Generated by: LCOV version 2.0-1