feat(web-ui): PipelineTab — 진행 중 파이프라인 카드 보드
This commit is contained in:
63
src/pages/music/components/PipelineCard.jsx
Normal file
63
src/pages/music/components/PipelineCard.jsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { cancelPipeline, publishPipeline } from '../../../api';
|
||||
|
||||
const STEP_LABELS = ['커버','영상','썸네','메타','검토','발행'];
|
||||
|
||||
function stepIndex(state) {
|
||||
if (state.startsWith('cover')) return 0;
|
||||
if (state.startsWith('video')) return 1;
|
||||
if (state.startsWith('thumb')) return 2;
|
||||
if (state.startsWith('meta')) return 3;
|
||||
if (state.startsWith('ai_review') || state.startsWith('publish_pending')) return 4;
|
||||
if (state.startsWith('publish')) return 5;
|
||||
if (state === 'published') return 6;
|
||||
return -1;
|
||||
}
|
||||
|
||||
export default function PipelineCard({ pipeline, onChanged }) {
|
||||
const i = stepIndex(pipeline.state);
|
||||
return (
|
||||
<div className="pipeline-card">
|
||||
<div className="pipeline-card__head">
|
||||
<h4>{pipeline.track_title || `Track #${pipeline.track_id}`}</h4>
|
||||
{!['published','cancelled','failed'].includes(pipeline.state) && (
|
||||
<button onClick={async () => { await cancelPipeline(pipeline.id); onChanged(); }}>
|
||||
취소
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="pipeline-progress">
|
||||
{STEP_LABELS.map((lbl, idx) => (
|
||||
<div key={lbl} className={`pipeline-dot ${idx <= i ? 'is-done' : ''} ${idx === i ? 'is-current' : ''}`}>
|
||||
<span>{lbl}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="pipeline-state">현재: {pipeline.state}</div>
|
||||
{pipeline.review && (
|
||||
<div className="pipeline-review">
|
||||
AI 검토: <strong>{pipeline.review.verdict}</strong>
|
||||
({pipeline.review.weighted_total}/100)
|
||||
</div>
|
||||
)}
|
||||
{pipeline.state === 'publish_pending' && (
|
||||
<button className="button primary"
|
||||
onClick={async () => { await publishPipeline(pipeline.id); onChanged(); }}>
|
||||
YouTube 업로드
|
||||
</button>
|
||||
)}
|
||||
{pipeline.youtube_video_id && (
|
||||
<a href={`https://youtu.be/${pipeline.youtube_video_id}`} target="_blank" rel="noreferrer">
|
||||
유튜브에서 보기
|
||||
</a>
|
||||
)}
|
||||
{pipeline.feedback && pipeline.feedback.length > 0 && (
|
||||
<details className="pipeline-feedback">
|
||||
<summary>피드백 히스토리 ({pipeline.feedback.length})</summary>
|
||||
{pipeline.feedback.map(f => (
|
||||
<div key={f.id}>• [{f.step}] {f.feedback_text}</div>
|
||||
))}
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user