foxygit / RPA-Remisser Log in
commits tags

/webui/frontend/src/components/InspectDialog.tsx · 4.09 KB

raw
import { useEffect, useRef, useState } from "react";
import { ApiError, api, type InspectRow, type Step } from "../lib/api";
import type { T } from "../lib/i18n";
import { uid } from "../lib/ids";

interface Props {
  open: boolean;
  t: T;
  onClose: () => void;
  onCreateStep: (step: Step) => void;
}

export function InspectDialog({ open, t, onClose, onCreateStep }: Props) {
  const ref = useRef<HTMLDialogElement>(null);
  const [windows, setWindows] = useState<string[]>([]);
  const [title, setTitle] = useState("");
  const [rows, setRows] = useState<InspectRow[]>([]);
  const [err, setErr] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    const d = ref.current;
    if (!d) return;
    if (open && !d.open) {
      d.showModal();
      setErr(null);
      setRows([]);
      api
        .desktopWindows()
        .then((w) => {
          setWindows(w);
          if (w.length) setTitle(w[0]);
        })
        .catch((e) => setErr(e instanceof ApiError && e.status === 501 ? t("inspect_unavailable") : String(e)));
    }
    if (!open && d.open) d.close();
  }, [open, t]);

  async function load() {
    if (!title) return;
    setBusy(true);
    setErr(null);
    try {
      setRows(await api.inspectWindow(title));
    } catch (e) {
      setErr(e instanceof ApiError ? String(e.detail) : String(e));
    } finally {
      setBusy(false);
    }
  }

  function selectorFor(row: InspectRow): { by: string; value: string } {
    if (row.auto_id) return { by: "auto_id", value: row.auto_id };
    if (row.name) return { by: "name", value: row.name };
    if (row.class_name) return { by: "class_name", value: row.class_name };
    return { by: "name", value: "" };
  }

  function makeStep(row: InspectRow, type: "desktop_click" | "desktop_type") {
    const sel = selectorFor(row);
    const step: Step = { type, id: uid(), by: sel.by, value: sel.value };
    if (row.control_type) step.control_type = row.control_type;
    if (type === "desktop_type") step.text = "";
    onCreateStep(step);
  }

  return (
    <dialog ref={ref} onClose={onClose} className="inspect-dialog">
      <h2>{t("inspect_window")}</h2>
      <p className="hint">{t("inspect_hint")}</p>
      <div className="inspect-controls">
        <select value={title} onChange={(e) => setTitle(e.target.value)}>
          {windows.length === 0 && <option value="">{t("inspect_none")}</option>}
          {windows.map((w) => (
            <option key={w} value={w}>
              {w}
            </option>
          ))}
        </select>
        <button onClick={load} disabled={busy || !title}>
          {busy ? "…" : t("inspect_load")}
        </button>
        <span className="spacer" />
        <button type="button" className="secondary" onClick={onClose}>
          {t("cancel")}
        </button>
      </div>
      {err && <p className="assist-msg error">{err}</p>}
      {rows.length > 0 && (
        <div className="inspect-table">
          {rows.map((row, i) => {
            const sel = selectorFor(row);
            return (
              <div className="inspect-row" key={i} style={{ paddingLeft: 8 + row.depth * 14 }}>
                <code className="inspect-ct">{row.control_type || "?"}</code>
                <span className="inspect-name">{row.name || <em>—</em>}</span>
                {row.auto_id && <code className="inspect-aid">#{row.auto_id}</code>}
                <span className="spacer" />
                <button
                  className="secondary tiny"
                  title={`${sel.by}=${sel.value}`}
                  onClick={() => navigator.clipboard?.writeText(`${sel.by}=${sel.value}`)}
                >
                  {t("inspect_copy")}
                </button>
                <button className="secondary tiny" onClick={() => makeStep(row, "desktop_click")}>
                  {t("inspect_make_click")}
                </button>
                <button className="secondary tiny" onClick={() => makeStep(row, "desktop_type")}>
                  {t("inspect_make_type")}
                </button>
              </div>
            );
          })}
        </div>
      )}
    </dialog>
  );
}