← Files Biological Sequence & Alignment ViewerARCHIVED FILE

src/biological-sequence-viewer.tsx

32.1 KB · Sep 30, 2026 · 23:01 UTC

↓ Download file

import clsx from "clsx";
import {
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
  useSyncExternalStore,
} from "react";

import { createArtifactStateKey } from "./artifact-state-key";
import type {
  BiologicalSequenceViewerMode,
  BiologicalSequenceViewerModel,
} from "./biological-sequence-viewer-model";
import type { ModelContextUpdate, ModelContextUpdater } from "./model-context";
import { MsaRichViewer } from "./msa/msa-rich-viewer";
import { parseMsa } from "./msa/parser";
import { SequenceDurableViewerStateContext } from "./persistent/durable-viewer-state";
import { createSequenceDocumentFromMsa } from "./sequence/msa-sequence-adapter";
import { SequenceRichViewer } from "./sequence/sequence-rich-viewer";
import { WorkbenchToolController } from "./ui/workbench-tool-controller";
import {
  hasPendingWorkbenchAction,
  hasPendingWorkbenchDialog,
  WorkbenchToolControllerContext,
} from "./ui/workbench-tools";
import type {
  QueuedSequenceViewerCommand,
  SequenceViewerCommandResult,
} from "./viewer-commands";
import type { SequenceWorkspaceArtifactPublisher } from "./views/workbench-persistence";
import type { SequenceWorkspaceTrackBrowserClient } from "./views/workspace-tracks";
import type { SequenceWorkspaceSessionClient } from "./views/workspace-sessions";
import { WorkspaceSessionDiscovery } from "./workspace-session-controls";

export type BiologicalSequenceViewerDisplayModeControl = {
  mode: "inline" | "fullscreen";
  pending: boolean;
  requestMode: (mode: "inline" | "fullscreen") => Promise<void>;
};

export function BiologicalSequenceViewer({
  browseWorkspaceTracks,
  contents,
  command,
  displayModeControl,
  fileName,
  initialToolbarVisible,
  model,
  onCommandResult,
  publishWorkspaceArtifact,
  sourceStateKey,
  updateModelContext,
  viewerSessionId,
  workspaceSessions,
}: {
  browseWorkspaceTracks?: SequenceWorkspaceTrackBrowserClient;
  contents: string;
  command?: QueuedSequenceViewerCommand;
  displayModeControl?: BiologicalSequenceViewerDisplayModeControl;
  fileName?: string;
  initialToolbarVisible?: boolean;
  model: BiologicalSequenceViewerModel;
  onCommandResult?: (
    command: QueuedSequenceViewerCommand,
    result: SequenceViewerCommandResult,
  ) => void;
  publishWorkspaceArtifact?: SequenceWorkspaceArtifactPublisher;
  sourceStateKey?: string;
  updateModelContext?: ModelContextUpdater;
  viewerSessionId?: string;
  workspaceSessions?: SequenceWorkspaceSessionClient;
}): React.ReactElement {
  const durableViewerState = useContext(SequenceDurableViewerStateContext);
  const resolvedSourceStateKey = useMemo(
    () => sourceStateKey ?? createArtifactStateKey(contents, fileName),
    [contents, fileName, sourceStateKey],
  );
  const getInitialToolbarVisibility = (): boolean =>
    (durableViewerState?.restoredState?.sourceStateKey ===
    resolvedSourceStateKey
      ? durableViewerState.restoredState.toolbarVisible
      : undefined) ??
    initialToolbarVisible ??
    true;
  const [toolbarVisible, setToolbarVisible] = useState(
    getInitialToolbarVisibility,
  );
  const [toolbarTemporarilyRevealed, setToolbarTemporarilyRevealed] =
    useState(false);
  const toolbarHeaderRef = useRef<HTMLElement | null>(null);
  const toolbarRevealZoneRef = useRef<HTMLButtonElement | null>(null);
  const viewerRef = useRef<HTMLDivElement | null>(null);
  const handledToolbarCommandIdRef = useRef<string | undefined>(undefined);
  const latestChildModelContextRef = useRef<{
    sourceStateKey: string;
    update: ModelContextUpdate;
  } | null>(null);
  const toolbarSourceActivationRef = useRef<{
    controller: typeof durableViewerState;
    initialToolbarVisible: boolean | undefined;
    sourceStateKey: string;
  }>({
    controller: durableViewerState,
    initialToolbarVisible,
    sourceStateKey: resolvedSourceStateKey,
  });
  const [mode, setMode] = useState<BiologicalSequenceViewerMode>(
    model.defaultMode,
  );
  const [modeNotice, setModeNotice] = useState<string | null>(null);
  const toolController = useMemo(
    () => new WorkbenchToolController(),
    [resolvedSourceStateKey],
  );
  const toolControllerVersion = useSyncExternalStore(
    toolController.subscribe,
    toolController.getVersion,
    toolController.getVersion,
  );
  const [generatedAlignment, setGeneratedAlignment] = useState<{
    contents: string;
    name: string;
  } | null>(null);
  const availableModes = useMemo(
    () =>
      generatedAlignment == null || model.availableModes.includes("alignment")
        ? model.availableModes
        : [...model.availableModes, "alignment" as const],
    [generatedAlignment, model.availableModes],
  );
  const activeMode = availableModes.includes(mode) ? mode : model.defaultMode;
  const commandMode =
    command == null
      ? activeMode
      : getCommandMode(command, activeMode, {
          alignmentMetrics: availableModes.includes("alignment"),
          sequenceMetrics: model.sequenceDocument?.fastqSummary != null,
        });
  const toolbarRevealed = toolbarVisible || toolbarTemporarilyRevealed;
  const changeMode = useCallback(
    (nextMode: BiologicalSequenceViewerMode): boolean => {
      if (nextMode === activeMode) return true;
      if (
        hasPendingWorkbenchDialog() ||
        (viewerRef.current != null &&
          hasPendingWorkbenchAction(viewerRef.current))
      ) {
        setModeNotice(
          "Finish or dismiss the pending action before changing viewer mode.",
        );
        return false;
      }
      setModeNotice(null);
      setMode(nextMode);
      return true;
    },
    [activeMode],
  );
  const setToolbarVisibility = useCallback(
    (visible: boolean): boolean => {
      if (!visible) {
        const activeDialog = document.querySelector(
          '[role="dialog"][aria-modal="true"], [role="alertdialog"], dialog[open]',
        );
        const activeToolbarFeedback = Array.from(
          viewerRef.current?.querySelectorAll<HTMLElement>(
            "[data-sequence-toolbar-controls]",
          ) ?? [],
        ).some(hasPendingWorkbenchAction);
        if (activeDialog != null || activeToolbarFeedback) {
          return false;
        }
        viewerRef.current?.focus({ preventScroll: true });
      }
      setToolbarVisible(visible);
      setToolbarTemporarilyRevealed(false);
      durableViewerState?.setToolbarVisibility({
        sourceStateKey: resolvedSourceStateKey,
        visible,
      });
      return true;
    },
    [durableViewerState, resolvedSourceStateKey],
  );
  const revealToolbar = useCallback(() => {
    if (!toolbarVisible) setToolbarTemporarilyRevealed(true);
  }, [toolbarVisible]);
  const dismissToolbar = useCallback(
    (nextTarget: EventTarget | null, preserveFocusedToolbar = true) => {
      if (toolbarVisible) return;
      const toolbarContains = (target: EventTarget | null): boolean =>
        target instanceof Node &&
        (toolbarHeaderRef.current?.contains(target) === true ||
          toolbarRevealZoneRef.current?.contains(target) === true ||
          Array.from(
            viewerRef.current?.querySelectorAll(
              "[data-sequence-toolbar-controls]",
            ) ?? [],
          ).some((controls) => controls.contains(target)));
      if (
        toolbarContains(nextTarget) ||
        (preserveFocusedToolbar && toolbarContains(document.activeElement))
      ) {
        return;
      }
      setToolbarTemporarilyRevealed(false);
    },
    [toolbarVisible],
  );
  const updateModelContextWithToolbar = useCallback<ModelContextUpdater>(
    (update) => {
      latestChildModelContextRef.current = {
        sourceStateKey: resolvedSourceStateKey,
        update,
      };
      const disclosures = toolController.getDisclosureSnapshots();
      const feedback = toolController.getFeedbackSnapshots();
      return updateModelContext?.({
        ...update,
        structuredContent: {
          ...update.structuredContent,
          toolbarVisible,
          workbenchPanels: toolController.getSnapshots(),
          workbenchDisclosures: {
            items: disclosures.slice(0, 50),
            totalCount: disclosures.length,
            truncated: disclosures.length > 50,
          },
          workbenchFeedback: {
            items: feedback.slice(0, 50),
            totalCount: feedback.length,
            truncated: feedback.length > 50,
          },
        },
        text: `${update.text}\nToolbar: ${toolbarVisible ? "visible" : "hidden"}`,
      });
    },
    [
      resolvedSourceStateKey,
      toolbarVisible,
      toolController,
      toolControllerVersion,
      updateModelContext,
    ],
  );

  // Child context is deduplicated by biological state. Republish only when
  // shared UI chrome changes, without asking it to fabricate a data change.
  useEffect(() => {
    const latest = latestChildModelContextRef.current;
    if (latest?.sourceStateKey !== resolvedSourceStateKey) return;
    void Promise.resolve(updateModelContextWithToolbar(latest.update)).catch(
      () => {
        // A host context failure must not make the local viewer unusable.
      },
    );
  }, [resolvedSourceStateKey, updateModelContextWithToolbar]);

  useEffect(() => {
    setMode(model.defaultMode);
    setModeNotice(null);
    setGeneratedAlignment(null);
  }, [contents, fileName, model.defaultMode]);

  useEffect(() => {
    const activation = toolbarSourceActivationRef.current;
    if (
      activation.controller === durableViewerState &&
      activation.initialToolbarVisible === initialToolbarVisible &&
      activation.sourceStateKey === resolvedSourceStateKey
    ) {
      return;
    }
    toolbarSourceActivationRef.current = {
      controller: durableViewerState,
      initialToolbarVisible,
      sourceStateKey: resolvedSourceStateKey,
    };
    const restoredVisibility =
      durableViewerState?.restoredState?.sourceStateKey ===
      resolvedSourceStateKey
        ? durableViewerState.restoredState.toolbarVisible
        : undefined;
    setToolbarVisible(restoredVisibility ?? initialToolbarVisible ?? true);
    setToolbarTemporarilyRevealed(false);
  }, [durableViewerState, initialToolbarVisible, resolvedSourceStateKey]);

  useEffect(() => {
    const activation = toolbarSourceActivationRef.current;
    if (
      activation.controller !== durableViewerState ||
      activation.initialToolbarVisible !== initialToolbarVisible ||
      activation.sourceStateKey !== resolvedSourceStateKey
    ) {
      return;
    }
    const restoredVisibility =
      durableViewerState?.restoredState?.sourceStateKey ===
      resolvedSourceStateKey
        ? durableViewerState.restoredState.toolbarVisible
        : undefined;
    if (restoredVisibility != null && restoredVisibility !== toolbarVisible) {
      return;
    }
    durableViewerState?.setToolbarVisibility({
      sourceStateKey: resolvedSourceStateKey,
      visible: toolbarVisible,
    });
  }, [
    durableViewerState,
    initialToolbarVisible,
    resolvedSourceStateKey,
    toolbarVisible,
  ]);

  useEffect(() => {
    if (command == null) {
      return;
    }
    if (command.action === "set_display_mode") {
      return;
    }
    if (handledToolbarCommandIdRef.current === command.commandId) return;
    if (command.action === "set_toolbar_visibility") {
      handledToolbarCommandIdRef.current = command.commandId;
      const applied = setToolbarVisibility(command.visible);
      onCommandResult?.(command, {
        applied,
        message: applied
          ? command.visible
            ? "Showed the viewer toolbar."
            : "Hid the viewer toolbar."
          : "The viewer toolbar cannot be hidden while an approval or copy action needs attention.",
        state: { toolbarVisible: applied ? command.visible : toolbarVisible },
      });
      return;
    }
    if (command.action === "set_mode") {
      handledToolbarCommandIdRef.current = command.commandId;
      if (command.mode == null || !availableModes.includes(command.mode)) {
        onCommandResult?.(command, {
          applied: false,
          message: "That display mode is not available for this artifact.",
        });
        return;
      }
      const applied = changeMode(command.mode);
      onCommandResult?.(command, {
        applied,
        message: applied
          ? `Switched the viewer to ${command.mode} mode.`
          : "Finish or dismiss the pending action before changing viewer mode.",
        state: { mode: applied ? command.mode : activeMode },
      });
      return;
    }
    if (!availableModes.includes(commandMode)) {
      handledToolbarCommandIdRef.current = command.commandId;
      onCommandResult?.(command, {
        applied: false,
        message: `${commandMode} mode is not available for this artifact.`,
        state: { availableModes, mode: activeMode },
      });
      return;
    }
    if (commandMode !== activeMode) {
      if (!changeMode(commandMode)) {
        handledToolbarCommandIdRef.current = command.commandId;
        onCommandResult?.(command, {
          applied: false,
          message:
            "Finish or dismiss the pending action before changing viewer mode.",
          state: { mode: activeMode },
        });
      }
      return;
    }
    if (command.action === "set_workbench_panel") {
      handledToolbarCommandIdRef.current = command.commandId;
      const result = toolController.setPanel(command.group, command.panel);
      if (
        result.applied &&
        command.panel != null &&
        command.group === "sequence-display"
      ) {
        setToolbarVisibility(true);
      }
      onCommandResult?.(command, result);
      return;
    }
    if (command.action === "set_workbench_disclosure") {
      handledToolbarCommandIdRef.current = command.commandId;
      const result = toolController.setDisclosure(
        command.disclosureId,
        command.expanded,
      );
      if (
        result.applied &&
        command.expanded &&
        toolController
          .getDisclosureSnapshots()
          .find(({ id }) => id === command.disclosureId)?.location?.group ===
          "sequence-display"
      ) {
        setToolbarVisibility(true);
      }
      onCommandResult?.(command, result);
      return;
    }
    if (command.action === "dismiss_workbench_feedback") {
      handledToolbarCommandIdRef.current = command.commandId;
      onCommandResult?.(
        command,
        toolController.dismissFeedback(command.feedbackId),
      );
      return;
    }
    if (
      command.action === "query_viewer" &&
      (command.request.target === "workbench-disclosures" ||
        command.request.target === "workbench-feedback")
    ) {
      handledToolbarCommandIdRef.current = command.commandId;
      try {
        const query =
          command.request.target === "workbench-disclosures"
            ? toolController.queryDisclosures(command.request)
            : toolController.queryFeedback(command.request);
        onCommandResult?.(command, {
          applied: true,
          message: `Returned the mounted ${command.request.target} state.`,
          state: { query },
        });
      } catch (error) {
        onCommandResult?.(command, {
          applied: false,
          message:
            error instanceof Error
              ? error.message
              : "The workbench UI state could not be queried.",
        });
      }
      return;
    }
    if (
      command.action === "query_viewer" &&
      command.request.target === "workbench-panels"
    ) {
      handledToolbarCommandIdRef.current = command.commandId;
      const panels = toolController.getSnapshots(command.request.group);
      onCommandResult?.(command, {
        applied: panels.length > 0,
        message:
          panels.length > 0
            ? `Returned ${panels.length} mounted workbench tool group${panels.length === 1 ? "" : "s"}.`
            : "That workbench tool group is not mounted for this artifact.",
        state: {
          query: {
            items: panels,
            nextCursor: null,
            page: {
              count: panels.length,
              offset: 0,
              totalCount: panels.length,
            },
            target: "workbench-panels",
            truncated: false,
          },
        },
      });
    }
  }, [
    activeMode,
    availableModes,
    changeMode,
    command,
    commandMode,
    onCommandResult,
    setToolbarVisibility,
    toolbarVisible,
    toolController,
    toolControllerVersion,
  ]);

  return (
    <WorkbenchToolControllerContext.Provider value={toolController}>
      <div
        className="sequence-viewer-shell flex min-h-screen w-full min-w-0 max-w-full flex-col overflow-x-hidden bg-token-main-surface-primary text-token-text-primary"
        data-toolbar-mode={toolbarVisible ? "pinned" : "hidden"}
        data-toolbar-revealed={toolbarRevealed}
        data-toolbar-visible={toolbarVisible}
        onBlurCapture={(event) => dismissToolbar(event.relatedTarget, false)}
        onFocusCapture={(event) => {
          if (
            event.target instanceof Element &&
            event.target.closest("[data-sequence-toolbar-controls]") != null
          ) {
            revealToolbar();
          }
        }}
        onPointerOut={(event) => {
          if (
            event.target instanceof Element &&
            event.target.closest("[data-sequence-toolbar-controls]") != null
          ) {
            dismissToolbar(event.relatedTarget);
          }
        }}
        onPointerOver={(event) => {
          if (
            event.target instanceof Element &&
            event.target.closest("[data-sequence-toolbar-controls]") != null
          ) {
            revealToolbar();
          }
        }}
        ref={viewerRef}
        tabIndex={-1}
      >
        {!toolbarVisible ? (
          <button
            aria-controls="sequence-viewer-topbar"
            aria-expanded={toolbarRevealed}
            aria-label="Reveal sequence viewer toolbar"
            className="sequence-toolbar-reveal-zone"
            onBlur={(event) => dismissToolbar(event.relatedTarget, false)}
            onClick={revealToolbar}
            onFocus={revealToolbar}
            onPointerEnter={revealToolbar}
            onPointerLeave={(event) => dismissToolbar(event.relatedTarget)}
            ref={toolbarRevealZoneRef}
            type="button"
          />
        ) : null}
        <BiologicalSequenceViewerHeader
          availableModes={availableModes}
          classification={model.classification.kind}
          displayModeControl={displayModeControl}
          fileName={fileName}
          headerRef={toolbarHeaderRef}
          mode={activeMode}
          onDismissToolbar={dismissToolbar}
          onModeChange={changeMode}
          onRevealToolbar={revealToolbar}
          onToolbarVisibilityChange={setToolbarVisibility}
          toolbarRevealed={toolbarRevealed}
          toolbarVisible={toolbarVisible}
        />
        {modeNotice == null ? null : (
          <p className="bio-workbench-tool-notice" role="status">
            {modeNotice}
          </p>
        )}
        <WorkspaceSessionDiscovery client={workspaceSessions} />
        {activeMode === "alignment" ? (
          <MsaRichViewer
            className="min-h-0 min-w-0 flex-1"
            command={
              command != null &&
              !isSharedWorkbenchCommand(command) &&
              commandMode === "alignment"
                ? command
                : undefined
            }
            contents={generatedAlignment?.contents ?? contents}
            fileName={generatedAlignment?.name ?? fileName}
            onCommandResult={onCommandResult}
            publishWorkspaceArtifact={publishWorkspaceArtifact}
            showFileHeader={false}
            sourceStateKeyOverride={
              generatedAlignment == null ? sourceStateKey : undefined
            }
            toolbarRevealed={toolbarRevealed}
            toolbarVisible={toolbarVisible}
            updateModelContext={
              updateModelContext == null
                ? undefined
                : updateModelContextWithToolbar
            }
            viewerSessionId={viewerSessionId}
            workspaceSessions={workspaceSessions}
          />
        ) : (
          <SequenceModeSurface
            command={
              command != null &&
              !isSharedWorkbenchCommand(command) &&
              commandMode === "sequence"
                ? command
                : undefined
            }
            contents={contents}
            browseWorkspaceTracks={browseWorkspaceTracks}
            fileName={fileName}
            model={model}
            onCommandResult={onCommandResult}
            onOpenAlignment={(alignedFasta, name) => {
              setGeneratedAlignment({ contents: alignedFasta, name });
              setMode("alignment");
            }}
            publishWorkspaceArtifact={publishWorkspaceArtifact}
            sourceStateKey={sourceStateKey}
            toolbarRevealed={toolbarRevealed}
            toolbarVisible={toolbarVisible}
            updateModelContext={
              updateModelContext == null
                ? undefined
                : updateModelContextWithToolbar
            }
            viewerSessionId={viewerSessionId}
            workspaceSessions={workspaceSessions}
          />
        )}
      </div>
    </WorkbenchToolControllerContext.Provider>
  );
}

function SequenceModeSurface({
  browseWorkspaceTracks,
  command,
  contents,
  fileName,
  model,
  onCommandResult,
  onOpenAlignment,
  publishWorkspaceArtifact,
  sourceStateKey,
  toolbarRevealed,
  toolbarVisible,
  updateModelContext,
  viewerSessionId,
  workspaceSessions,
}: {
  browseWorkspaceTracks?: SequenceWorkspaceTrackBrowserClient;
  command?: QueuedSequenceViewerCommand;
  contents: string;
  fileName?: string;
  model: BiologicalSequenceViewerModel;
  onCommandResult?: (
    command: QueuedSequenceViewerCommand,
    result: SequenceViewerCommandResult,
  ) => void;
  onOpenAlignment?: (alignedFasta: string, name: string) => void;
  publishWorkspaceArtifact?: SequenceWorkspaceArtifactPublisher;
  sourceStateKey?: string;
  toolbarRevealed?: boolean;
  toolbarVisible?: boolean;
  updateModelContext?: ModelContextUpdater;
  viewerSessionId?: string;
  workspaceSessions?: SequenceWorkspaceSessionClient;
}): React.ReactElement {
  const artifactStateKey = useMemo(
    () => sourceStateKey ?? createArtifactStateKey(contents, fileName),
    [contents, fileName, sourceStateKey],
  );
  const sequenceDocument = useMemo(() => {
    if (model.sequenceDocument != null) {
      return model.sequenceDocument;
    }
    if (!model.alignmentAvailable) {
      return null;
    }
    const parseResult = parseMsa(contents, fileName);
    return parseResult.status === "success"
      ? createSequenceDocumentFromMsa({
          classification: model.classification,
          document: parseResult.document,
          fileName,
        })
      : null;
  }, [contents, fileName, model]);

  return sequenceDocument == null ? (
    <EmptyViewerState>
      No generic sequence projection is available for this biological artifact.
    </EmptyViewerState>
  ) : (
    <SequenceRichViewer
      browseWorkspaceTracks={browseWorkspaceTracks}
      command={command}
      document={sequenceDocument}
      key={artifactStateKey}
      onCommandResult={onCommandResult}
      onOpenAlignment={onOpenAlignment}
      publishWorkspaceArtifact={publishWorkspaceArtifact}
      sourceStateKeyOverride={artifactStateKey}
      toolbarRevealed={toolbarRevealed}
      toolbarVisible={toolbarVisible}
      updateModelContext={updateModelContext}
      viewerSessionId={viewerSessionId}
      workspaceSessions={workspaceSessions}
    />
  );
}

function isSharedWorkbenchCommand(
  command: QueuedSequenceViewerCommand,
): boolean {
  return (
    command.action === "set_mode" ||
    command.action === "set_display_mode" ||
    command.action === "set_toolbar_visibility" ||
    command.action === "set_workbench_panel" ||
    command.action === "set_workbench_disclosure" ||
    command.action === "dismiss_workbench_feedback" ||
    (command.action === "query_viewer" &&
      (command.request.target === "workbench-panels" ||
        command.request.target === "workbench-disclosures" ||
        command.request.target === "workbench-feedback"))
  );
}

function getCommandMode(
  command: QueuedSequenceViewerCommand,
  currentMode: BiologicalSequenceViewerMode,
  metricsCapabilities: {
    alignmentMetrics: boolean;
    sequenceMetrics: boolean;
  },
): BiologicalSequenceViewerMode {
  if (command.action === "set_workbench_panel") {
    return command.group === "alignment-tools" ? "alignment" : "sequence";
  }
  if (command.action === "set_workbench_disclosure") {
    return command.disclosureId.startsWith("alignment.")
      ? "alignment"
      : "sequence";
  }
  if (command.action === "dismiss_workbench_feedback") {
    return command.feedbackId.startsWith("alignment.")
      ? "alignment"
      : "sequence";
  }
  if (
    command.action === "set_read_pileup_options" ||
    command.action === "select_read" ||
    command.action === "clear_read_selection" ||
    command.action === "set_quality_view_options" ||
    command.action === "set_chromatogram_view_options"
  ) {
    return "sequence";
  }
  if (command.action === "restore_session" && command.mode != null) {
    return command.mode;
  }
  if (command.action === "align_sequences") {
    if (command.rowIds != null) return "alignment";
    if (command.recordIds != null) return "sequence";
    return currentMode;
  }
  if (command.action.includes("alignment")) return "alignment";
  if (command.action.includes("sequence")) return "sequence";
  if (command.action === "run_analysis") {
    return command.request.analysis === "build-tree" ||
      command.request.analysis === "distance-matrix"
      ? "alignment"
      : "sequence";
  }
  if (command.action === "edit_copy") {
    if (command.request.operation.includes("alignment")) return "alignment";
    if (
      command.request.operation === "insert-sequence" ||
      command.request.operation === "delete-sequence-range" ||
      command.request.operation === "replace-sequence-range" ||
      command.request.operation === "reverse-complement-range" ||
      command.request.operation === "rotate-sequence"
    ) {
      return "sequence";
    }
  }
  if (command.action === "manage_annotations") return "sequence";
  if (command.action === "query_viewer") {
    if (
      command.request.target === "workbench-disclosures" ||
      command.request.target === "workbench-feedback"
    )
      return command.request.mode ?? currentMode;
    if (
      command.request.target === "workbench-panels" &&
      command.request.group != null
    ) {
      return command.request.group === "alignment-tools"
        ? "alignment"
        : "sequence";
    }
    if (command.request.target === "metrics") {
      if (
        (currentMode === "sequence" && metricsCapabilities.sequenceMetrics) ||
        (currentMode === "alignment" && metricsCapabilities.alignmentMetrics)
      ) {
        return currentMode;
      }
      return metricsCapabilities.alignmentMetrics ? "alignment" : "sequence";
    }
    if (["columns", "rows", "tree-nodes"].includes(command.request.target)) {
      return "alignment";
    }
    if (
      [
        "chromatogram",
        "coverage",
        "features",
        "quality",
        "quality-report",
        "read-detail",
        "read-pileup-state",
        "reads",
        "records",
        "sequence-range",
        "sequence-ui-state",
        "variants",
      ].includes(command.request.target)
    ) {
      return "sequence";
    }
  }
  if (command.action === "export_artifact") {
    if (["aligned-fasta", "newick"].includes(command.format)) {
      return "alignment";
    }
    if (command.format === "svg") return currentMode;
    if (
      ["bed", "embl", "fasta", "fastq", "genbank", "gff3", "vcf"].includes(
        command.format,
      )
    ) {
      return "sequence";
    }
  }
  return currentMode;
}

function BiologicalSequenceViewerHeader({
  availableModes,
  classification,
  displayModeControl,
  fileName,
  headerRef,
  mode,
  onDismissToolbar,
  onModeChange,
  onRevealToolbar,
  onToolbarVisibilityChange,
  toolbarRevealed,
  toolbarVisible,
}: {
  availableModes: Array<BiologicalSequenceViewerMode>;
  classification: BiologicalSequenceViewerModel["classification"]["kind"];
  displayModeControl?: BiologicalSequenceViewerDisplayModeControl;
  fileName?: string;
  headerRef: React.RefObject<HTMLElement | null>;
  mode: BiologicalSequenceViewerMode;
  onDismissToolbar: (
    nextTarget: EventTarget | null,
    preserveFocusedToolbar?: boolean,
  ) => void;
  onModeChange: (mode: BiologicalSequenceViewerMode) => void;
  onRevealToolbar: () => void;
  onToolbarVisibilityChange: (visible: boolean) => void;
  toolbarRevealed: boolean;
  toolbarVisible: boolean;
}): React.ReactElement {
  return (
    <header
      className="sequence-viewer-topbar sticky top-0 z-20 border-b border-token-border bg-token-main-surface-primary"
      id="sequence-viewer-topbar"
      inert={!toolbarRevealed ? true : undefined}
      onBlur={(event) => onDismissToolbar(event.relatedTarget, false)}
      onFocus={onRevealToolbar}
      onPointerEnter={onRevealToolbar}
      onPointerLeave={(event) => onDismissToolbar(event.relatedTarget)}
      ref={headerRef}
    >
      <div className="bio-viewer-header">
        <div className="bio-viewer-identity">
          <span aria-hidden="true" className="bio-viewer-file-mark">
            {mode === "alignment" ? "≡" : "Aa"}
          </span>
          <div className="min-w-0">
            <div className="bio-viewer-file-name" title={fileName}>
              {fileName ?? "Biological sequence"}
            </div>
            <div className="bio-viewer-file-kind">
              {formatArtifactKind(classification)}
            </div>
          </div>
        </div>
        {availableModes.length > 1 ? (
          <nav
            aria-label="Biological Sequence & Alignment Viewer mode"
            className="bio-viewer-mode-switch"
          >
            {availableModes.map((availableMode) => (
              <button
                aria-pressed={mode === availableMode}
                className={clsx(
                  "bio-viewer-mode-button",
                  mode === availableMode
                    ? "bio-viewer-mode-button-active"
                    : "text-token-text-secondary hover:text-token-text-primary",
                )}
                key={availableMode}
                onClick={() => onModeChange(availableMode)}
                type="button"
              >
                {availableMode === "alignment" ? "Alignment" : "Sequence"}
              </button>
            ))}
          </nav>
        ) : null}
        {displayModeControl ? (
          <button
            className="bio-viewer-header-action"
            disabled={displayModeControl.pending}
            onClick={() =>
              void displayModeControl.requestMode(
                displayModeControl.mode === "fullscreen"
                  ? "inline"
                  : "fullscreen",
              )
            }
            type="button"
          >
            {displayModeControl.mode === "fullscreen"
              ? "Return to chat"
              : "Open in side pane"}
          </button>
        ) : null}
        <button
          aria-label={toolbarVisible ? "Hide toolbar" : "Show toolbar"}
          className="bio-viewer-header-action"
          onClick={() => onToolbarVisibilityChange(!toolbarVisible)}
          title={
            toolbarVisible
              ? "Hide the toolbar until you hover or focus the top edge"
              : "Keep the toolbar visible"
          }
          type="button"
        >
          {toolbarVisible ? "Hide" : "Show"}
        </button>
      </div>
    </header>
  );
}

function EmptyViewerState({
  children,
}: {
  children: React.ReactNode;
}): React.ReactElement {
  return (
    <div className="flex min-h-0 flex-1 items-center justify-center p-6 text-sm text-token-text-secondary">
      {children}
    </div>
  );
}

function formatArtifactKind(
  kind: BiologicalSequenceViewerModel["classification"]["kind"],
): string {
  switch (kind) {
    case "annotated-sequence":
      return "Annotated sequence";
    case "chromatogram":
      return "Chromatogram";
    case "fastq":
      return "FASTQ reads";
    case "multiple-sequence-alignment":
      return "Multiple sequence alignment";
    case "sequence-collection":
      return "Sequence collection";
    case "single-sequence":
      return "Single sequence";
    case "unknown":
      return "Biological sequence artifact";
  }
}

SHA-256: 332ef25d1876893df539b7445b9af7f239dbe621050a0cf8a90fd544a6db18d8