LCOV - code coverage report
Current view: top level - dashql-app/src/app - hyper_links.ts Coverage Total Hit
Test: DashQL 6e74948 Lines: 100.0 % 45 45
Test Date: 2026-11-06 17:46:50

            Line data    Source code
       1              : import * as React from 'react';
       2              : 
       3              : import { useConnectionAllocator, useConnectionRegistryStore } from '../connections/connection_registry.js';
       4              : import { useConnectionSaver } from '../connections/connection_persistence.js';
       5              : import { connectionLabel } from '../connections/connection_label.js';
       6              : import { useDashQLCoreSetup } from '../runtime/core_provider.js';
       7              : import { OPEN_LINK_SESSION, useRouteContext, useRouterNavigate } from './router/router.js';
       8              : import { sessionConnectionIds, type SessionScripts } from '../session/scripts/session_scripts.js';
       9              : import { useSessionScriptsRegistryReader } from '../session/scripts/session_scripts_registry.js';
      10              : import { useSessionCreation } from '../session/session_creation.js';
      11              : import type { ConnectionState } from '../connections/connection_state.js';
      12              : import { usePlatformEventListener } from '../platform/events/event_listener_provider.js';
      13              : import { useLogger } from '../platform/logger/logger_provider.js';
      14              : import { stringifyError } from '../platform/logger/logger.js';
      15              : import { bindHyperLink, confirmHyperLink, getHyperLinkTabState, isHyperLinkParams, setHyperLinkToken, type HyperLinkTarget } from '../connections/hyper/hyper_link.js';
      16              : 
      17            1 : const LOG_CTX = 'hyper_link';
      18              : 
      19              : /// The session that a link opens: the open session if it runs on the connection of the link, otherwise the first
      20              : /// session on it, null if a new one is needed
      21            1 : export function sessionOnConnection(sessions: Map<string, SessionScripts>, currentSessionId: string | null, connectionId: string): string | null {
      22            1 :     const current = currentSessionId == null ? undefined : sessions.get(currentSessionId);
      23            1 :     if (current != null && sessionConnectionIds(current).includes(connectionId)) return currentSessionId;
      24            1 :     for (const [sessionId, scripts] of sessions) {
      25            1 :         if (sessionConnectionIds(scripts).includes(connectionId)) return sessionId;
      26              :     }
      27            1 :     return null;
      28            1 : }
      29              : 
      30              : /// Ask whether a link reuses the connection of an earlier link
      31            1 : function confirmReuse(connection: ConnectionState, target: HyperLinkTarget): boolean {
      32            1 :     const endpoint = 'hyper' in connection.params ? connection.params.hyper.endpoint : '';
      33            1 :     return globalThis.confirm(`Use the connection "${connectionLabel(connection)}" to ${endpoint} for the Hyper at ${target.endpoint}? Cancel creates a new connection.`);
      34            1 : }
      35              : 
      36              : /// Follow the Hyper links, of the page and of the native app.
      37              : ///
      38              : /// A link is handled once the app opened its first session: a link to another machine is confirmed, the link is bound
      39              : /// to a connection (see `bindHyperLink`), the connection takes the token of the link and new sessions start on it.
      40              : /// The app then opens a session on the connection, or creates one.
      41            1 : export function useHyperLinks(opened: Promise<void>): void {
      42            1 :     const appEvents = usePlatformEventListener();
      43            1 :     const logger = useLogger();
      44            1 :     const setupCore = useDashQLCoreSetup();
      45            1 :     const registryStore = useConnectionRegistryStore();
      46            1 :     const allocate = useConnectionAllocator();
      47            1 :     const saveConnection = useConnectionSaver();
      48            1 :     const readSessions = useSessionScriptsRegistryReader();
      49            1 :     const createSession = useSessionCreation();
      50            1 :     const navigate = useRouterNavigate();
      51            1 :     const route = useRouteContext();
      52              : 
      53            1 :     const follow = React.useEffectEvent(async (target: HyperLinkTarget) => {
      54            1 :         const dql = await setupCore(LOG_CTX);
      55            1 :         const connections = [...registryStore.current.connections.values()];
      56            1 :         const known = connections.some(connection => isHyperLinkParams(connection.params)
      57            1 :             && 'hyper' in connection.params && connection.params.hyper.endpoint === target.endpoint);
      58            1 :         if (!known && !confirmHyperLink(target)) return;
      59            1 :         const binding = bindHyperLink(target, connections, allocate, dql, getHyperLinkTabState().current,
      60            1 :             connection => confirmReuse(connection, target));
      61            1 :         if (binding.params != null) await saveConnection(binding.connection.connectionId, binding.params);
      62            1 :         setHyperLinkToken(binding.connection.connectionId, target.token);
      63            1 :         const sessions = readSessions().sessionScriptsMap;
      64            1 :         const sessionId = sessionOnConnection(sessions, route.sessionId ?? null, binding.connection.connectionId)
      65            1 :             ?? createSession(binding.connection).sessionId;
      66            1 :         if (sessionId !== route.sessionId) navigate({ type: OPEN_LINK_SESSION, value: sessionId });
      67            1 :     });
      68              : 
      69            1 :     React.useEffect(() => appEvents.subscribeHyperLinks(target => {
      70            1 :         logger.info('Received a Hyper link', { endpoint: target.endpoint }, LOG_CTX);
      71            1 :         void opened
      72            1 :             .then(() => follow(target))
      73            1 :             .catch(error => logger.error('Failed to follow a Hyper link', { error: stringifyError(error) }, LOG_CTX));
      74            1 :     }), [appEvents, logger, opened]);
      75            1 : }
        

Generated by: LCOV version 2.0-1