summaryrefslogblamecommitdiff
path: root/makima/frontend/src/components/directives/OrchestratorStepNode.tsx
blob: 9c8e95ee8077f9d906ee582ca1efd9860536075c (plain) (tree)
































































































































































                                                                                                                             
export type OrchestratorStepType =
  | "planning"
  | "replanning"
  | "plan-orders"
  | "pr"
  | "pr-update"
  | "cleanup"
  | "verification";

export type OrchestratorStepStatus = "running" | "completed" | "failed" | "pending";

export interface OrchestratorStepNodeProps {
  type: OrchestratorStepType;
  taskId: string;
  status: OrchestratorStepStatus;
  label: string;
  hasQuestions?: boolean;
}

const TYPE_COLORS: Record<
  OrchestratorStepType,
  { accent: string; bg: string; border: string; text: string; dot: string }
> = {
  planning: {
    accent: "#75aafc",
    bg: "bg-[#0d1a30]",
    border: "border-[#75aafc]",
    text: "text-[#75aafc]",
    dot: "bg-[#75aafc]",
  },
  replanning: {
    accent: "#75aafc",
    bg: "bg-[#0d1a30]",
    border: "border-[#75aafc]",
    text: "text-[#75aafc]",
    dot: "bg-[#75aafc]",
  },
  "plan-orders": {
    accent: "#c084fc",
    bg: "bg-[#1a0d30]",
    border: "border-[#c084fc]",
    text: "text-[#c084fc]",
    dot: "bg-[#c084fc]",
  },
  pr: {
    accent: "#34d399",
    bg: "bg-[#0a1a14]",
    border: "border-[#34d399]",
    text: "text-[#34d399]",
    dot: "bg-[#34d399]",
  },
  "pr-update": {
    accent: "#34d399",
    bg: "bg-[#0a1a14]",
    border: "border-[#34d399]",
    text: "text-[#34d399]",
    dot: "bg-[#34d399]",
  },
  cleanup: {
    accent: "#7788aa",
    bg: "bg-[#141a24]",
    border: "border-[#7788aa]",
    text: "text-[#7788aa]",
    dot: "bg-[#7788aa]",
  },
  verification: {
    accent: "#7788aa",
    bg: "bg-[#141a24]",
    border: "border-[#7788aa]",
    text: "text-[#7788aa]",
    dot: "bg-[#7788aa]",
  },
};

const TYPE_LABELS: Record<OrchestratorStepType, string> = {
  planning: "PLANNING",
  replanning: "REPLANNING",
  "plan-orders": "PLAN ORDERS",
  pr: "PR",
  "pr-update": "PR UPDATE",
  cleanup: "CLEANUP",
  verification: "VERIFICATION",
};

const STATUS_LABELS: Record<OrchestratorStepStatus, string> = {
  pending: "PENDING",
  running: "RUNNING",
  completed: "DONE",
  failed: "FAILED",
};

export function OrchestratorStepNode({
  type,
  taskId,
  status,
  label,
  hasQuestions,
}: OrchestratorStepNodeProps) {
  const colors = TYPE_COLORS[type];
  const typeLabel = TYPE_LABELS[type];
  const statusLabel = STATUS_LABELS[status];

  return (
    <div
      className={`${colors.bg} ${colors.border} border border-dashed rounded px-3 py-2 min-w-[160px] max-w-[220px] relative`}
    >
      {/* Type badge */}
      <div className="flex items-center justify-between gap-2 mb-1">
        <div className="flex items-center gap-1.5 min-w-0">
          {/* Status dot */}
          {status === "running" && (
            <span
              className={`inline-block w-2 h-2 rounded-full ${colors.dot} animate-pulse shrink-0`}
            />
          )}
          {status === "completed" && (
            <span className="inline-block w-2 h-2 rounded-full bg-emerald-400 shrink-0" />
          )}
          {status === "failed" && (
            <span className="inline-block w-2 h-2 rounded-full bg-red-400 shrink-0" />
          )}
          {status === "pending" && (
            <span className="inline-block w-2 h-2 rounded-full bg-[#556677] shrink-0" />
          )}
          <span className={`text-[9px] font-mono ${colors.text} uppercase shrink-0`}>
            {typeLabel}
          </span>
        </div>
        <div className="flex items-center gap-1 shrink-0">
          {hasQuestions && (
            <span className="inline-block w-2 h-2 rounded-full bg-purple-400 animate-pulse" title="Has pending questions" />
          )}
          <span
            className={`text-[9px] font-mono uppercase ${
              status === "completed"
                ? "text-emerald-400"
                : status === "failed"
                ? "text-red-400"
                : colors.text
            }`}
          >
            {statusLabel}
          </span>
        </div>
      </div>

      {/* Label */}
      <span className="text-[11px] font-mono text-white truncate block font-medium mb-1">
        {label}
      </span>

      {/* Task link */}
      <a
        href={`/mesh/${taskId}`}
        className={`text-[9px] font-mono text-[#556677] hover:${colors.text} underline block`}
      >
        {status === "running" ? "View running task" : "View task"}
      </a>
    </div>
  );
}