From b67b3f8e8d63361d9ff19f87fd608c03bfa3fd43 Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Tue, 17 Feb 2026 00:40:32 +0000
Subject: soryu-co/soryu - makima (#67)

* feat: soryu-co/soryu - makima: Fix contracts page scrolling overflow

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* feat: soryu-co/soryu - makima: Remove contract association from orders and make directive mandatory in UI

* feat: soryu-co/soryu - makima: Add directive name to order metadata for searchability

* feat: soryu-co/soryu - makima: Change directive link in orders to use search interface

* feat: soryu-co/soryu - makima: Name directive PRs based on content not directive title

* feat: soryu-co/soryu - makima: Add orderId to step creation and auto-link orders to steps

* feat: soryu-co/soryu - makima: Add under_review status and auto-complete orders in plan flow
---
 .../frontend/src/components/orders/OrderDetail.tsx | 117 ++++++++++++++++-----
 1 file changed, 92 insertions(+), 25 deletions(-)

(limited to 'makima/frontend/src/components/orders/OrderDetail.tsx')

diff --git a/makima/frontend/src/components/orders/OrderDetail.tsx b/makima/frontend/src/components/orders/OrderDetail.tsx
index 9d4c00c..1b8d76e 100644
--- a/makima/frontend/src/components/orders/OrderDetail.tsx
+++ b/makima/frontend/src/components/orders/OrderDetail.tsx
@@ -11,6 +11,7 @@ import type {
 const STATUS_BADGE: Record<OrderStatus, { color: string; label: string }> = {
   open: { color: "text-[#75aafc] border-[rgba(117,170,252,0.4)]", label: "OPEN" },
   in_progress: { color: "text-yellow-400 border-yellow-800", label: "IN PROGRESS" },
+  under_review: { color: "text-amber-400 border-amber-800", label: "UNDER REVIEW" },
   done: { color: "text-emerald-400 border-emerald-800", label: "DONE" },
   archived: { color: "text-[#556677] border-[#2a3a5a]", label: "ARCHIVED" },
 };
@@ -31,7 +32,7 @@ const TYPE_OPTIONS: { value: OrderType; color: string; label: string }[] = [
   { value: "improvement", color: "text-emerald-400", label: "Improvement" },
 ];
 
-const STATUS_OPTIONS: OrderStatus[] = ["open", "in_progress", "done", "archived"];
+const STATUS_OPTIONS: OrderStatus[] = ["open", "in_progress", "under_review", "done", "archived"];
 
 interface OrderDetailProps {
   order: Order;
@@ -59,6 +60,7 @@ export function OrderDetail({
   const [editingLabels, setEditingLabels] = useState(false);
   const [labelsText, setLabelsText] = useState(order.labels.join(", "));
   const [showLinkDirective, setShowLinkDirective] = useState(false);
+  const [directiveSearch, setDirectiveSearch] = useState("");
 
   const badge = STATUS_BADGE[order.status] || STATUS_BADGE.open;
   const currentPriority = PRIORITY_OPTIONS.find((p) => p.value === order.priority) || PRIORITY_OPTIONS[4];
@@ -405,31 +407,96 @@ export function OrderDetail({
         <div className="flex flex-col gap-2">
           {/* Link to Directive */}
           <div>
-            <button
-              type="button"
-              onClick={() => setShowLinkDirective(!showLinkDirective)}
-              className="text-[10px] font-mono text-[#75aafc] hover:text-white border border-[rgba(117,170,252,0.3)] rounded px-2 py-1 w-full text-left"
-            >
-              Link to Directive
-            </button>
+            <div className="flex items-center gap-1.5">
+              <button
+                type="button"
+                onClick={() => {
+                  setShowLinkDirective(!showLinkDirective);
+                  setDirectiveSearch("");
+                }}
+                className="text-[10px] font-mono text-[#75aafc] hover:text-white border border-[rgba(117,170,252,0.3)] rounded px-2 py-1 flex-1 text-left"
+              >
+                {order.directiveId ? "Change Directive" : "Link to Directive"}
+              </button>
+              {order.directiveId && (
+                <button
+                  type="button"
+                  onClick={() => onUpdate({ directiveId: null, directiveStepId: null })}
+                  className="text-[10px] font-mono text-red-400 hover:text-red-300 border border-red-800 rounded px-2 py-1"
+                  title="Unlink directive"
+                >
+                  Unlink
+                </button>
+              )}
+            </div>
             {showLinkDirective && (
-              <div className="mt-1 border border-[rgba(117,170,252,0.2)] bg-[#0a1525] max-h-32 overflow-y-auto rounded">
-                {directives.length === 0 ? (
-                  <div className="px-3 py-2 text-[10px] font-mono text-[#556677]">
-                    No directives available
-                  </div>
-                ) : (
-                  directives.map((d) => (
-                    <button
-                      key={d.id}
-                      type="button"
-                      onClick={() => handleLinkDirective(d.id)}
-                      className="w-full text-left px-3 py-1.5 text-[10px] font-mono text-[#9bc3ff] hover:bg-[rgba(117,170,252,0.1)] border-b border-[rgba(117,170,252,0.1)] last:border-b-0"
-                    >
-                      {d.title}
-                    </button>
-                  ))
-                )}
+              <div className="mt-1 border border-[rgba(117,170,252,0.2)] bg-[#0a1525] rounded">
+                <div className="px-2 py-1.5 border-b border-[rgba(117,170,252,0.1)]">
+                  <input
+                    type="text"
+                    value={directiveSearch}
+                    onChange={(e) => setDirectiveSearch(e.target.value)}
+                    placeholder="Search directives..."
+                    autoFocus
+                    className="w-full bg-transparent border-none outline-none text-[10px] font-mono text-[#75aafc] placeholder-[#556677]"
+                  />
+                </div>
+                <div className="max-h-32 overflow-y-auto">
+                  {directives.length === 0 ? (
+                    <div className="px-3 py-2 text-[10px] font-mono text-[#556677]">
+                      No directives available
+                    </div>
+                  ) : (
+                    (() => {
+                      const filtered = directives.filter((d) =>
+                        d.title.toLowerCase().includes(directiveSearch.toLowerCase())
+                      );
+                      if (filtered.length === 0) {
+                        return (
+                          <div className="px-3 py-2 text-[10px] font-mono text-[#556677]">
+                            No matching directives
+                          </div>
+                        );
+                      }
+                      return filtered.map((d) => {
+                        const isLinked = d.id === order.directiveId;
+                        const statusColors: Record<string, string> = {
+                          draft: "text-[#556677] border-[#2a3a5a]",
+                          active: "text-emerald-400 border-emerald-800",
+                          idle: "text-[#7788aa] border-[#2a3a5a]",
+                          paused: "text-yellow-400 border-yellow-800",
+                          archived: "text-[#556677] border-[#2a3a5a]",
+                        };
+                        const sColor = statusColors[d.status] || statusColors.draft;
+                        return (
+                          <button
+                            key={d.id}
+                            type="button"
+                            onClick={() => handleLinkDirective(d.id)}
+                            className={`w-full text-left px-3 py-1.5 text-[10px] font-mono hover:bg-[rgba(117,170,252,0.1)] border-b border-[rgba(117,170,252,0.1)] last:border-b-0 ${
+                              isLinked ? "bg-[rgba(117,170,252,0.08)] text-white" : "text-[#9bc3ff]"
+                            }`}
+                          >
+                            <div className="flex items-center gap-1.5">
+                              <span className={`shrink-0 text-[8px] font-mono ${sColor} border rounded px-1 py-0.5 uppercase`}>
+                                {d.status}
+                              </span>
+                              <span className="truncate">{d.title}</span>
+                              {isLinked && (
+                                <span className="shrink-0 text-[8px] text-emerald-400">●</span>
+                              )}
+                            </div>
+                            {d.repositoryUrl && (
+                              <div className="text-[8px] text-[#556677] truncate mt-0.5">
+                                {d.repositoryUrl}
+                              </div>
+                            )}
+                          </button>
+                        );
+                      });
+                    })()
+                  )}
+                </div>
               </div>
             )}
           </div>
-- 
cgit v1.2.3

