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

            Line data    Source code
       1              : import * as React from 'react';
       2              : import symbols from '@ankoh/dashql-svg-symbols';
       3              : 
       4              : import * as styles from './session_connection_buttons.module.css';
       5              : 
       6              : import { AnchorSide } from '../../ui/foundations/anchored_position.js';
       7              : import { ButtonSize, ButtonVariant, IconButton } from '../../ui/foundations/button.js';
       8              : import { ConnectionHealth, type ConnectionState } from '../../connections/connection_state.js';
       9              : import { CONNECTION_HEALTH_COLORS, CONNECTION_HEALTH_NAMES } from '../../connections/connection_status.js';
      10              : import { ConnectionSettingsOverlay } from '../../connections/connection_settings_overlay.js';
      11              : import { connectionLabelText } from '../../connections/connection_label.js';
      12              : import { useConnectionLabeler } from '../connection_labels.js';
      13              : import { CONNECTOR_ICON_STYLE, useConnectorIcon } from '../../connections/connector_icon.js';
      14              : 
      15              : interface Props {
      16              :     /// The connections that the scripts of the session and the next script run on
      17              :     connections: readonly ConnectionState[];
      18              :     /// The session asks for attention to its connections, e.g. when a blocked run button is hovered
      19              :     attention: boolean;
      20              : }
      21              : 
      22              : export interface SessionConnectionButtonsDependencies {
      23              :     ConnectionSettingsOverlay: typeof ConnectionSettingsOverlay;
      24              : }
      25              : 
      26            1 : const DEFAULT_DEPENDENCIES: SessionConnectionButtonsDependencies = {
      27            1 :     ConnectionSettingsOverlay,
      28            1 : };
      29              : 
      30              : /// The connections that the scripts of a session and its next script run on, a connector logo with a health dot each.
      31              : ///
      32              : /// The user sees which connection is not connected yet. A button opens the settings of its connection,
      33              : /// nothing connects by itself.
      34            1 : export function SessionConnectionButtons(props: Props & { dependencies?: SessionConnectionButtonsDependencies }): React.ReactElement | null {
      35            1 :     const connectorIcon = useConnectorIcon();
      36            1 :     const dependencies = props.dependencies ?? DEFAULT_DEPENDENCIES;
      37            1 :     const labeler = useConnectionLabeler();
      38            1 :     const [settingsConnectionId, setSettingsConnectionId] = React.useState<string | null>(null);
      39            1 :     const anchorRef = React.useRef<HTMLButtonElement | null>(null);
      40            1 :     if (props.connections.length === 0) return null;
      41            1 :     return (
      42            1 :         <div className={styles.buttons} role="group" aria-label="Connections of the session" data-testid="session-connections">
      43            1 :             {props.connections.map(connection => {
      44            1 :                 const health = connection.connectionHealth;
      45            1 :                 const label = `${connectionLabelText(labeler(connection))}: ${CONNECTION_HEALTH_NAMES[health]}`;
      46            1 :                 return (
      47            1 :                     <IconButton
      48            1 :                         key={connection.connectionId}
      49            1 :                         className={styles.button}
      50            1 :                         variant={ButtonVariant.Invisible}
      51            1 :                         size={ButtonSize.Small}
      52            1 :                         aria-label={label}
      53            1 :                         data-testid="session-connection"
      54            1 :                         data-health={ConnectionHealth[health]}
      55            1 :                         data-attention={props.attention && health !== ConnectionHealth.ONLINE ? '' : undefined}
      56            1 :                         onClick={event => {
      57            1 :                             anchorRef.current = event.currentTarget;
      58            1 :                             setSettingsConnectionId(connection.connectionId);
      59            1 :                         }}
      60              :                     >
      61            1 :                         <span className={styles.logo}>
      62            1 :                             <svg width="16px" height="16px" aria-hidden="true">
      63            1 :                                 <use xlinkHref={`${symbols}#${connectorIcon(connection.connectorInfo)}`} style={CONNECTOR_ICON_STYLE} />
      64            1 :                             </svg>
      65            1 :                             <svg className={styles.health} width="10px" height="10px" viewBox="0 0 10 10" aria-hidden="true">
      66            1 :                                 <circle cx="5" cy="5" r="5" style={{ fill: 'var(--color_bg_card)' }} />
      67            1 :                                 <circle cx="5" cy="5" r="3.5" style={{ fill: CONNECTION_HEALTH_COLORS[health] }} />
      68            1 :                             </svg>
      69            1 :                         </span>
      70            1 :                     </IconButton>
      71              :                 );
      72            1 :             })}
      73              :             {/* Mounted only while open, the overlay subscribes to the connection */}
      74            1 :             {settingsConnectionId != null && (
      75            1 :                 <dependencies.ConnectionSettingsOverlay
      76            1 :                     connectionId={settingsConnectionId}
      77            1 :                     isOpen
      78            1 :                     onClose={() => setSettingsConnectionId(null)}
      79            1 :                     anchorRef={anchorRef}
      80            1 :                     side={AnchorSide.OutsideBottom}
      81            1 :                 />
      82              :             )}
      83            1 :         </div>
      84              :     );
      85            1 : }
        

Generated by: LCOV version 2.0-1