feat(my-deepagent): v0.4 — workflow generator UI + hot-reload + UX polish

브라우저에서 YAML 안 쓰고도 새 워크플로우 템플릿 만들기 + 즉시 등록.
+ /new.html / index.html / new-workflow.html / runs.html / conversation.html
의 nav·copy·empty-state 정비.

A. /new.html UX:
- 제목 "새 Run" → "워크플로우 실행 (고급)"
- 상단 info-box: "자유 대화는 여기가 아닙니다 → 메인 페이지"
- 모든 필드에 한 줄 hint
- Persona 오버라이드 <details> 접힘

B. Nav 재정렬 (5 페이지):
- "대화" nav-primary, 나머지 nav-secondary (작고 dim)

C. 메인 안내 + CSS:
- 메인 / 에 "👋 my-deepagent" info-box 추가
- .info-box / .nav-primary / .nav-secondary / .wf-* 신규 스타일

D. Workflow hot-reload:
- api/deps.py get_workflows 가 매 요청 mtime 튜플 검사 후 변경 시 reload
- lifespan 도 user dir 포함하도록 _load_workflows_combined

E. Workflow generator:
- POST /api/workflows: CreateWorkflowRequest → WorkflowTemplate validate →
  <data_dir>/workflows/<name>@<version>.yaml 저장.  중복 409, validation 422.
- static/new-workflow.html: 기본 정보 / Roles / Phases / YAML preview
- app.js bootstrapWorkflowGenerator: capability chip 토글, role select 동적,
  실시간 YAML preview, XSS 정책 유지

테스트 (test_workflow_generator.py, 7 신규):
- 페이지 200 + 마크업
- POST happy / 422 (empty roles) / 422 (unknown role) / 409 (dup)
- GET hot-reload after POST
- GET hot-reload after external file drop

게이트:
- ruff / format / mypy: PASS (142 source files)
- pytest -q --ignore=tests/integration/test_e2e_workflow.py
  --ignore=tests/integration/test_openrouter_smoke.py: 709 passed (+7 신규)
- 라이브 smoke: / / new.html / new-workflow.html 모두 200, screenshot OK

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
chungyeong
2026-05-18 00:38:46 +09:00
parent 40ef833ad3
commit 6d371afadd
14 changed files with 1007 additions and 52 deletions

View File

@@ -962,3 +962,134 @@ select {
cursor: not-allowed;
}
/* =================================================================
v0.4 — nav tiers + info-box + empty-state polish
================================================================= */
nav .nav-primary {
font-weight: 600;
}
nav .nav-secondary {
font-size: 12.5px;
opacity: 0.65;
}
nav .nav-secondary:hover {
opacity: 1;
}
nav a.active.nav-primary,
nav a.active.nav-secondary {
opacity: 1;
}
.info-box {
background: rgba(245, 158, 11, 0.08);
border: 1px solid rgba(245, 158, 11, 0.3);
border-left: 4px solid rgb(245, 158, 11);
padding: 14px 18px;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
line-height: 1.65;
color: rgb(95, 50, 5);
}
.info-box strong {
color: rgb(75, 35, 0);
}
.info-box a {
color: rgb(180, 70, 30);
text-decoration: underline;
text-underline-offset: 2px;
}
/* details/summary polish */
details summary {
padding: 4px 0;
}
details[open] summary {
margin-bottom: 12px;
}
/* index empty state — prominent CTA */
.empty-cta {
text-align: center;
padding: 64px 20px;
}
.empty-cta-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
color: var(--text);
}
.empty-cta-subtitle {
color: var(--text-muted);
font-size: 14px;
margin-bottom: 24px;
}
.empty-cta .button {
font-size: 15px;
padding: 12px 24px;
}
/* =================================================================
v0.4 — workflow generator UI
================================================================= */
.wf-row-card {
background: var(--bg);
border: 1px solid var(--border);
border-radius: 8px;
padding: 14px 16px;
margin-bottom: 12px;
}
.wf-row-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px dashed var(--border);
}
.button-link {
background: none;
border: none;
color: rgb(180, 70, 30);
cursor: pointer;
font-size: 12px;
text-decoration: underline;
padding: 2px 6px;
}
.wf-chip {
display: inline-flex;
align-items: center;
gap: 4px;
background: rgba(180, 70, 30, 0.06);
border: 1px solid rgba(180, 70, 30, 0.2);
border-radius: 999px;
padding: 3px 10px;
font-size: 12.5px;
cursor: pointer;
margin: 2px 4px 2px 0;
}
.wf-chip input {
margin: 0;
}
.wf-chip:has(input:checked) {
background: rgba(180, 70, 30, 0.18);
border-color: rgba(180, 70, 30, 0.5);
font-weight: 600;
}