feat: FastAPI console with dashboard, Pulp client, healthz (stages 0-1)
- config: PULP_* env + 사내 CA(verify=) 대응 - pulp_client: Basic Auth get/post/patch, status/list_repos/get_version - BFF 라우트: GET / (대시보드), GET /repos (조각), GET /healthz - views: Pulp JSON → 표시 모델 (GPG 검증 배지 3단계, 요약 집계) - HTMX + Jinja 템플릿, vendored pico.css/htmx.js (CDN 의존 0) - 브라우저는 Pulp 직접 호출 안 함 — 모두 BFF 경유 (스펙 §2) - 테스트: pulp_client(respx), 라우트(dependency_overrides), views 순수함수 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
22
app/templates/base.html
Normal file
22
app/templates/base.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}Pulp 패치 관리 콘솔{% endblock %}</title>
|
||||
<!-- 정적 자산은 폐쇄망 대비 local 동봉 (CDN 의존 금지, 스펙 §9) -->
|
||||
<link rel="stylesheet" href="/static/pico.min.css">
|
||||
<link rel="stylesheet" href="/static/app.css">
|
||||
<script src="/static/htmx.min.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="app-nav">
|
||||
<div class="container">
|
||||
<p class="brand"><span class="accent">Pulp</span> 패치 관리 콘솔</p>
|
||||
</div>
|
||||
</nav>
|
||||
<main class="container">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
21
app/templates/dashboard.html
Normal file
21
app/templates/dashboard.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<section>
|
||||
<h2>상태</h2>
|
||||
<!-- 로드 시 1회 + 10초마다 Pulp 연결 상태 폴링 -->
|
||||
<div hx-get="/healthz" hx-trigger="load, every 10s" hx-swap="innerHTML" style="margin-top:12px;">
|
||||
<span class="status-line status-loading">연결 확인 중…</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="section-head">
|
||||
<h2>저장소</h2>
|
||||
<button hx-get="/repos" hx-target="#repo-list" hx-swap="outerHTML" class="secondary">
|
||||
새로고침
|
||||
</button>
|
||||
</div>
|
||||
{% include "partials/repo_list.html" %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
5
app/templates/partials/health.html
Normal file
5
app/templates/partials/health.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{% if online %}
|
||||
<span class="status-line status-ok">{{ detail }}</span>
|
||||
{% else %}
|
||||
<span class="status-line status-bad">{{ detail }}</span>
|
||||
{% endif %}
|
||||
46
app/templates/partials/repo_list.html
Normal file
46
app/templates/partials/repo_list.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<div id="repo-list">
|
||||
{% if error %}
|
||||
<p role="alert" class="status-line status-bad">저장소 목록을 불러오지 못했습니다: {{ error }}</p>
|
||||
{% else %}
|
||||
<div class="summary">
|
||||
<div class="card"><div class="value">{{ summary.total }}</div><div class="label">전체 저장소</div></div>
|
||||
<div class="card"><div class="value">{{ summary.syncing }}</div><div class="label">동기화 중</div></div>
|
||||
<div class="card"><div class="value">{{ summary.gpg_pass }}</div><div class="label">GPG 검증 통과</div></div>
|
||||
<div class="card"><div class="value">{{ summary.total_packages }}</div><div class="label">총 패키지</div></div>
|
||||
</div>
|
||||
|
||||
{% if repos %}
|
||||
<div class="table-card">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>저장소</th>
|
||||
<th>검증</th>
|
||||
<th class="num">최신 버전</th>
|
||||
<th class="num">패키지 수</th>
|
||||
<th>마지막 동기화</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for repo in repos %}
|
||||
<tr>
|
||||
<td class="repo-name">{{ repo.name }}</td>
|
||||
<td><span class="badge badge-{{ repo.gpg.level }}">{{ repo.gpg.label }}</span></td>
|
||||
<td class="num">{% if repo.latest_version is not none %}v{{ repo.latest_version }}{% else %}—{% endif %}</td>
|
||||
<td class="num">{% if repo.package_count is not none %}{{ repo.package_count }}{% else %}—{% endif %}</td>
|
||||
<td>{{ repo.last_sync or "—" }}</td>
|
||||
<td>
|
||||
<!-- 동기화 버튼은 단계2에서 동작 연결 -->
|
||||
<button disabled class="secondary">동기화</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p>등록된 저장소가 없습니다.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
Reference in New Issue
Block a user