You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
// frontend/components/tasks/ScaffoldPanel.tsx — Auto-Scaffolding (업무 쪼개기)
|
|
"use client";
|
|
import { useState } from "react";
|
|
import { Icon } from "@/components/Icon";
|
|
import { tasksApi } from "@/lib/tasks/api";
|
|
import type { ScaffoldResult } from "@/lib/types";
|
|
|
|
export function ScaffoldPanel({
|
|
taskId,
|
|
show,
|
|
onApplied,
|
|
}: {
|
|
taskId: string;
|
|
show: boolean; // 완료 작업이면 트리거 숨김
|
|
onApplied: () => void;
|
|
}) {
|
|
const [preview, setPreview] = useState<ScaffoldResult | null>(null);
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
const trigger = async () => {
|
|
setBusy(true);
|
|
try {
|
|
const r = await tasksApi.scaffold(taskId, { create: false });
|
|
setPreview(r);
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
};
|
|
|
|
const apply = async () => {
|
|
setBusy(true);
|
|
try {
|
|
await tasksApi.scaffold(taskId, { create: true });
|
|
setPreview(null);
|
|
onApplied();
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
};
|
|
|
|
if (preview) {
|
|
return (
|
|
<div className="scaffold-panel">
|
|
<div className="sp-head">
|
|
<span className="sp-ic">
|
|
<Icon name="spark" />
|
|
</span>
|
|
<div className="sp-h">
|
|
<b>{preview.kind} 워크플로우 추천</b>
|
|
<span>{preview.items.length}단계 · 예상 시간 자동 배분</span>
|
|
</div>
|
|
<button className="sp-x" onClick={() => setPreview(null)} aria-label="닫기">
|
|
<Icon name="x" />
|
|
</button>
|
|
</div>
|
|
<div className="sp-items">
|
|
{preview.items.map((it, i) => (
|
|
<div className="sp-item" key={i}>
|
|
<span className="sp-num">{i + 1}</span>
|
|
<span className="sp-title">{it.title}</span>
|
|
<span className="sp-est">
|
|
<Icon name="clock" />
|
|
{it.est}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="sp-foot">
|
|
<button className="sp-ghost" onClick={() => setPreview(null)}>
|
|
닫기
|
|
</button>
|
|
<button className="sp-apply" onClick={apply} disabled={busy}>
|
|
<Icon name="plus" />
|
|
{preview.items.length}개 하위 작업 모두 추가
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!show) return null;
|
|
return (
|
|
<button className="scaffold-trigger" onClick={trigger} disabled={busy}>
|
|
<span className="st-ic">
|
|
<Icon name="wand" />
|
|
</span>
|
|
<span className="st-tx">
|
|
<b>아리에게 업무 쪼개기 맡기기</b>
|
|
<span>이 작업을 단계별 하위 작업으로 자동 분해하고 예상 시간을 배분해요</span>
|
|
</span>
|
|
<Icon name="arrow" />
|
|
</button>
|
|
);
|
|
}
|