fix+style: deploy modal/banner, back button, table stability

버그픽스
- 배포 확정 활성화: tojson 따옴표가 oninput 속성을 깨뜨리던 것 → data-confirm 비교로 수정
- ghost 버튼 호버 시 글자 하얘짐 → 호버 색 명시(새로고침/페이저/테마토글 공통)

UX/디자인
- 배포 모달: 취소·배포확정 한 줄, 저장소명만 mono, 순 변화 +초록/−빨강, 표 chrome 제거
- 배포 성공: 별도 다이얼로그 제거 → 모달 닫힘 + 배지 이동 + 완료 배너(여백·크기 정돈)
- 대시보드 백링크: ghost 버튼 + 화살표, 제목과 간격 확보
- 표 액션 셀 고정 박스(172x36) → 동기화/완료/진행 전환 시 행·열 안 흔들림
  (완료 'v3', 진행 'n/m·NN%', 실패는 축약+title 로 사유)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-17 16:53:01 +09:00
parent 59134927d8
commit bfd84fe94a
6 changed files with 153 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
<dialog open>
<article>
<article class="deploy-modal">
<header>
<h3>이 버전을 운영망에 배포</h3>
</header>
@@ -8,34 +8,43 @@
<p class="status-line status-bad">{{ error }}</p>
{% endif %}
<p>운영 서버(yum/dnf)가 실제로 내려받는 버전이 바뀝니다. 신중히 확인하세요.</p>
<p class="deploy-note">운영 서버(yum/dnf)가 실제로 내려받는 버전이 바뀝니다. 신중히 확인하세요.</p>
{% if preview %}
<table>
<table class="deploy-preview">
<tbody>
<tr><td>현재 운영</td>
<td class="num">{% if preview.current_version is not none %}v{{ preview.current_version }} ({{ preview.current_count }}개){% else %}없음{% endif %}</td></tr>
<tr><td>배포 대상</td>
<td class="num">v{{ preview.target_version }} ({{ preview.target_count }}개)</td></tr>
<tr><td>순 변화</td>
<td class="num">{{ preview.net_sign }}{{ preview.net }}개</td></tr>
<tr>
<th>현재 운영</th>
<td class="num">{% if preview.current_version is not none %}v{{ preview.current_version }} · {{ preview.current_count }}개{% else %}없음{% endif %}</td>
</tr>
<tr>
<th>배포 대상</th>
<td class="num">v{{ preview.target_version }} · {{ preview.target_count }}개</td>
</tr>
<tr>
<th>순 변화</th>
<td class="num">
<span class="{{ 'delta-add' if preview.net_sign == '+' else 'delta-del' }}">{{ preview.net_sign }}{{ preview.net }}개</span>
</td>
</tr>
</tbody>
</table>
{% endif %}
<form hx-post="/repos/{{ uuid }}/deploy" hx-target="#modal" hx-swap="innerHTML">
<input type="hidden" name="version_href" value="{{ version_href }}">
<label>
확인을 위해 저장소 이름 <strong>{{ repo_name }}</strong> 을(를) 입력하세요
<input type="text" name="confirm_name" autocomplete="off" required
oninput="document.getElementById('deploy-confirm-btn').disabled = (this.value !== {{ repo_name | tojson }})">
<label class="confirm-label">
확인을 위해 저장소 이름 <strong class="mono">{{ repo_name }}</strong> 을(를) 입력하세요
<input type="text" name="confirm_name" autocomplete="off" required class="mono"
data-confirm="{{ repo_name }}"
oninput="document.getElementById('deploy-confirm-btn').disabled = (this.value !== this.dataset.confirm)">
</label>
{# TODO(auth): 로그인 도입 시 여기서 배포 비밀번호 재확인 입력 추가 #}
<footer>
<button type="button" class="secondary"
{# TODO(auth): 로그인 도입 시 배포 비밀번호 재확인 입력 추가 #}
<div class="modal-actions">
<button type="button" class="ghost"
onclick="document.getElementById('modal').innerHTML=''">취소</button>
<button type="submit" id="deploy-confirm-btn" class="danger" disabled>배포 확정</button>
</footer>
</div>
</form>
</article>
</dialog>

View File

@@ -1,20 +1,12 @@
{# 배포 성공: 버전 목록 OOB 갱신 + flash 배너 + 모달 자리에 완료 알림 #}
{# 배포 성공: (1) 버전 목록 OOB 갱신 → 배지 이동, (2) 완료 배너 OOB,
(3) 본문은 비움 → #modal 닫힘. 별도 성공 다이얼로그/닫기 버튼 없음. #}
{% set oob = true %}
{% include "partials/version_list.html" %}
<div id="flash" hx-swap-oob="true">
<p class="status-line status-ok">
배포 완료 · v{{ to_version }}{% if from_version is not none %} (이전 v{{ from_version }}){% endif %}
{% if not audit_ok %} — ⚠ 감사 로그 기록 실패{% endif %}
</p>
<div class="flash-banner">
<span class="flash-dot"></span>
<span>배포 완료 · <strong class="mono">v{{ to_version }}</strong>{% if from_version is not none %} <span class="flash-sub">(이전 v{{ from_version }})</span>{% endif %}</span>
{% if not audit_ok %}<span class="flash-warn">감사 로그 기록 실패</span>{% endif %}
</div>
</div>
<dialog open>
<article>
<header><h3>배포 완료</h3></header>
<p>운영 배포 버전이 <strong>v{{ to_version }}</strong> 로 교체되었습니다.</p>
<footer>
<button onclick="document.getElementById('modal').innerHTML=''">닫기</button>
</footer>
</article>
</dialog>

View File

@@ -1,20 +1,21 @@
{# 진행률 바 조각. running 일 때만 hx-trigger 를 달아 3초 폴링; 완료/실패 시 폴링 중단. #}
{# 진행률 바 조각. running 일 때만 hx-trigger 를 달아 3초 폴링; 완료/실패 시 폴링 중단.
내용은 .row-action 고정 박스(172x36) 안에 들어오도록 짧게 유지. #}
<div id="prog-{{ uuid }}"
{% if progress.running %}hx-get="/repos/{{ uuid }}/progress" hx-trigger="every 3s" hx-swap="outerHTML"{% endif %}>
{% if progress.failed %}
<span class="status-line status-bad">동기화 실패: {{ progress.error }}</span>
<span class="status-line status-bad" title="{{ progress.error }}">동기화 실패</span>
{% elif progress.completed %}
<span class="badge badge-pass">동기화 완료{% if progress.new_version %} · v{{ progress.new_version }} 생성됨{% endif %}</span>
<span class="badge badge-pass">완료{% if progress.new_version %} · v{{ progress.new_version }}{% endif %}</span>
{% elif progress.idle %}
{# 추적 중인 작업 없음 — 빈 조각 #}
{% else %}
<div class="sync-progress">
{% if progress.total %}
<progress value="{{ progress.done }}" max="{{ progress.total }}"></progress>
<small class="num">{{ progress.done }}/{{ progress.total }} 패키지 · {{ progress.percent }}%</small>
<small class="num">{{ progress.done }}/{{ progress.total }} · {{ progress.percent }}%</small>
{% else %}
<progress></progress>
<small>동기화 준비 중…</small>
<small>준비 중…</small>
{% endif %}
</div>
{% endif %}