All files / src/components/tools ToolSearchCard.tsx

6.06% Statements 4/66
100% Branches 0/0
0% Functions 0/2
6.06% Lines 4/66

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 931x   1x                       1x     1x                                                                                                                                                      
import { useState, type JSX } from "react";
import type { ToolCardProps } from "./ToolCardProps.js";
import styles from "./toolCards.module.scss";
 
/** Extracts query from ToolSearch args. */
function getQuery(args: unknown): string {
  if (args === null || args === undefined || typeof args !== "object") {
    return "";
  }
  const a = args as Record<string, unknown>;
  return typeof a.query === "string" ? a.query : "";
}
 
/** Number of lines shown when collapsed. */
const PREVIEW_LINES: number = 8;
 
/** Renders a ToolSearch call (Claude Code built-in) with query and results. */
export function ToolSearchCard({ args, result, isError }: ToolCardProps): JSX.Element {
  const [expanded, setExpanded] = useState(false);
  const query = getQuery(args);
  const inProgress = result === undefined;
 
  const resultLines = result?.split("\n") ?? [];
  const hasMore = resultLines.length > PREVIEW_LINES;
  const displayResult = expanded ? result : resultLines.slice(0, PREVIEW_LINES).join("\n");
 
  return (
    <div
      className={`${styles.card} ${isError ? styles.cardRed : styles.cardNeutral} ${inProgress ? styles.inProgress : ""}`}
      data-testid="tool-card-tool-search"
    >
      <div className={styles.header}>
        <span className={styles.icon} aria-hidden="true">
          &#x1F527;
        </span>
        <span className={styles.toolName}>ToolSearch</span>
        {query && (
          <span className={styles.fileName} data-testid="tool-card-tool-search-query">
            &quot;{query}&quot;
          </span>
        )}
        {!inProgress && !isError && result && (
          <>
            <span className={styles.spacer} />
            <span className={styles.badge} data-testid="tool-card-tool-search-count">
              {resultLines.length} lines
            </span>
          </>
        )}
      </div>
 
      {/* In-progress: show query */}
      {inProgress && !query && args !== null && args !== undefined && (
        <pre className={styles.pre} data-testid="tool-card-args">
          {JSON.stringify(args, null, 2)}
        </pre>
      )}
 
      {/* Error */}
      {isError && result && (
        <pre className={styles.pre} data-testid="tool-card-error">
          {result}
        </pre>
      )}
 
      {/* Result text */}
      {!isError && !inProgress && result && (
        <>
          <pre className={styles.pre} data-testid="tool-card-tool-search-result">
            {displayResult}
          </pre>
          {hasMore && (
            <button
              type="button"
              className={styles.bodyToggle}
              onClick={() => {
                setExpanded((v) => !v);
              }}
              aria-expanded={expanded}
              data-testid="tool-card-toggle"
            >
              <span className={`${styles.chevron} ${expanded ? styles.chevronExpanded : ""}`}>
                &#x25B8;
              </span>
              {expanded ? "collapse" : `${resultLines.length - PREVIEW_LINES} more lines`}
            </button>
          )}
        </>
      )}
    </div>
  );
}