Ripple

tcmts.share.Ripple · #5ejwy5yc · term · runs anywhere

What the change touches, as a row: added, edited, removed; what re-hashed because of them; the tests they reach.

import { leafOf } from "#codebase/tcmts/share";
import type { ContributionChanges } from "#codebase/tcmts/share";

export function Ripple({ ch }: { ch: ContributionChanges }) {
  const items = ch.items;
  const col = (cls: string, names: string[]) =>
    names.length ? (
      <div className="col">
        {names.slice(0, 3).map((n) => (
          <span key={n} className={`node ${cls}`}>
            {leafOf(n)}
          </span>
        ))}
        {names.length > 3 && <span className={`node ${cls}`}>+{names.length - 3}</span>}
      </div>
    ) : null;
  const rehashed = ch.propagated.filter((p) => !p.test).length;
  const cols = [
    col(
      "a",
      items.filter((i) => i.change === "added" && !i.test).map((i) => i.path),
    ),
    col(
      "e",
      items
        .filter((i) => ["edited", "reworded", "renamed"].includes(i.change) && !i.test)
        .map((i) => i.path),
    ),
    col(
      "r",
      items.filter((i) => i.change === "removed").map((i) => i.path),
    ),
    rehashed ? (
      <div className="col">
        <span className="node p">{rehashed} re-hashed</span>
      </div>
    ) : null,
    col("t", [
      ...items.filter((i) => i.test && i.change !== "removed").map((i) => i.path),
      ...ch.propagated.filter((p) => p.test).map((p) => p.path),
    ]),
  ].filter((x) => x !== null);
  return (
    <div className="box">
      <div className="boxhead">
        <b>What it touches</b>
        <span className="muted">
          added and edited, what re-hashed because of them, and the tests they reach
        </span>
      </div>
      <div className="ripple">
        {cols.map((x, i) => (
          <span key={i} style={{ display: "contents" }}>
            {i > 0 && <span className="edge" />}
            {x}
          </span>
        ))}
      </div>
    </div>
  );
}

uses

used by